/* ==========================================================================
   Kushology — main styles
   ========================================================================== */

/* --- Scroll-reveal animations ------------------------------------------- */
.js-anim .reveal { opacity: 0; transform: translateY(26px); }
.js-anim .reveal.is-visible {
	opacity: 1; transform: none;
	transition: opacity .6s cubic-bezier(.2,.6,.2,1), transform .6s cubic-bezier(.2,.6,.2,1);
	transition-delay: var(--reveal-delay, 0ms);
}
@media (prefers-reduced-motion: reduce) {
	.js-anim .reveal, .js-anim .reveal.is-visible { opacity: 1; transform: none; transition: none; }
	html { scroll-behavior: auto; }
}
/* scroll-padding-top clears the 86px fixed header for EVERY in-page anchor
   (#main, #categories, #featured, #weekly-deals, #newsletter-signup…), which a
   per-id scroll-margin-top only ever fixed one target at a time. */
html { scroll-behavior: smooth; scrollbar-gutter: stable; scroll-padding-top: 120px; }

/* --- Reset / base ------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; overflow-x: clip; }
body {
	margin: 0;
	font-family: var(--font-sans);
	font-weight: var(--fw-regular);
	font-size: var(--fs-body);
	line-height: var(--lh-body);
	color: var(--c-text);
	background: var(--c-white);
	-webkit-font-smoothing: antialiased;
	overflow-x: clip; /* guard against off-canvas drawer / full-bleed overflow (clip won't break sticky) */
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 { margin: 0; font-weight: var(--fw-medium); line-height: var(--lh-tight); }
p { margin: 0; }
button { font-family: inherit; cursor: pointer; }
ul { margin: 0; padding: 0; list-style: none; }

.screen-reader-text {
	position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
	overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.skip-link { position: absolute; left: -9999px; top: 0; z-index: 1000; }
.skip-link:focus { left: 8px; padding: 8px 16px; background: #fff; border-radius: 8px; }

/* --- Layout ------------------------------------------------------------- */
.container {
	width: 100%;
	max-width: calc(var(--container) - var(--container-pad) * 0);
	margin-inline: auto;
	padding-inline: var(--container-pad);
}
.section { padding-block: var(--section-py); }
.section--sm { padding-block: var(--section-py-sm); }

/* Decorative green glows behind sections (Figma ellipse glows). Painted on a
   full-bleed pseudo-element: the sections are .container boxes (max-width),
   so a background on the element itself gets a hard clip at the container
   edge on wide viewports instead of fading out at the viewport edge.
   The box extends 512px above/below the section so the tints bleed into
   neighbouring sections like the Figma ellipses (which overflow their frames);
   gradient Y = calc(f% + (512 − f·1024)px) keeps each centre anchored at
   fraction f of the SECTION box despite the taller pseudo-element. */
.section--glow-left, .section--glow-right, .section--glow-both, .section--glow-categories,
.section--glow-deals, .section--glow-recommend, .section--glow-city, .section--glow-faq,
.section--glow-wd-weekly, .section--glow-wd-faq,
.section--glow-page-left, .section--glow-page-right { position: relative; }
.section--glow-left::before, .section--glow-right::before, .section--glow-both::before, .section--glow-categories::before,
.section--glow-deals::before, .section--glow-recommend::before, .section--glow-city::before, .section--glow-faq::before,
.section--glow-wd-weekly::before, .section--glow-wd-faq::before,
.section--glow-page-left::before, .section--glow-page-right::before {
	content: ""; position: absolute; top: -512px; bottom: -512px; left: 50%; width: 100vw;
	transform: translateX(-50%); background-repeat: no-repeat;
	pointer-events: none; z-index: -1;
	/* Fade the box's own top and bottom edges.
	   These gradients are positioned in percentages of the box, so when a section
	   grows the ellipse can end up larger than the 1024px of slack above/below it
	   and gets CLIPPED mid-fade — which paints a hard horizontal line across the
	   page. That is exactly what happened under the deals page CTA: the wd-faq
	   ellipse reached 246px past its own box bottom and cut off at y=5113, where
	   two overlapping glows abruptly became one.
	   Masking the edges makes that impossible for every glow, now and after any
	   content change, instead of hand-tuning each gradient's geometry and having
	   it break again the next time a section gets taller. */
	-webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 180px, #000 calc(100% - 180px), transparent 100%);
	mask-image: linear-gradient(to bottom, transparent 0, #000 180px, #000 calc(100% - 180px), transparent 100%);
}
.section--glow-left::before {
	background-image: radial-gradient(760px 560px at -8% calc(18% + 328px), rgba(216,244,160,0.55), rgba(216,244,160,0) 55%);
}
.section--glow-right::before {
	background-image: radial-gradient(760px 560px at 108% calc(22% + 287px), rgba(216,244,160,0.55), rgba(216,244,160,0) 55%);
}
/* Categories (Figma 20215:3233 in Frame 30): #D8F4A0 @ 0.3, 547×434 σ100,
   centre 455px right of frame centre, 39.4% down (pokes above the section). */
.section--glow-categories::before {
	background-image: radial-gradient(747px 634px at calc(50% + 455px) calc(39.4% + 109px), rgba(216,244,160,0.3) 46%, rgba(216,244,160,0) 100%);
}
/* Deals (Figma 20220:395 in Frame 38): same ellipse, 41.2% down. */
.section--glow-deals::before {
	background-image: radial-gradient(747px 634px at calc(50% + 455px) calc(41.2% + 90px), rgba(216,244,160,0.3) 46%, rgba(216,244,160,0) 100%);
}
/* Recommend (Figma 20215:3468 in Frame 36): wider 683×434 σ100 ellipse, centred. */
.section--glow-recommend::before {
	background-image: radial-gradient(883px 634px at 50% calc(31.9% + 186px), rgba(216,244,160,0.3) 55%, rgba(216,244,160,0) 100%);
}
/* Around the city (Figma 20228:425 in Frame 32): same ellipse, right of centre. */
.section--glow-city::before {
	background-image: radial-gradient(883px 634px at calc(50% + 467px) calc(69.1% - 196px), rgba(216,244,160,0.3) 55%, rgba(216,244,160,0) 100%);
}
/* FAQ (Figma 20228:421 in Frame 37): same ellipse, bottom-left. */
.section--glow-faq::before {
	background-image: radial-gradient(883px 634px at calc(50% - 306px) calc(93.9% - 449px), rgba(216,244,160,0.3) 55%, rgba(216,244,160,0) 100%);
}
/* Weed Deals page — weekly discounts (Figma 20228:752 in Frame 38): the E4
   547×434 σ100 ellipse, centre 455px right, 42.9% down the 1050px frame. */
.section--glow-wd-weekly::before {
	background-image: radial-gradient(747px 634px at calc(50% + 455px) calc(42.9% + 73px), rgba(216,244,160,0.3) 46%, rgba(216,244,160,0) 100%);
}
/* Interior pages — generic head glows: the same E4 547×434 σ100 ellipse
   family as the homepage tints, anchored 128px below the section top (640px
   into the ±512px-extended pseudo box) so shop / contact / checkout / search /
   404 / prose pages carry the brand gradient behind their page head without
   per-page Figma geometry. */
.section--glow-page-left::before {
	background-image: radial-gradient(747px 634px at calc(50% - 455px) 640px, rgba(216,244,160,0.3) 46%, rgba(216,244,160,0) 100%);
}
.section--glow-page-right::before {
	background-image: radial-gradient(747px 634px at calc(50% + 455px) 640px, rgba(216,244,160,0.3) 46%, rgba(216,244,160,0) 100%);
}
/* Weed Deals page — FAQ (Figma 20228:869 in Frame 37): E6 683×434 σ100
   ellipse, 306px left of centre, centre 745px below the 616px frame's top —
   mostly clipped below the section, tinting its bottom edge. */
.section--glow-wd-faq::before {
	background-image: radial-gradient(883px 634px at calc(50% - 306px) calc(120.9% - 726px), rgba(216,244,160,0.3) 55%, rgba(216,244,160,0) 100%);
}
/* Featured products (Figma 20215:3226 + 20215:3237): #D8F4A0 ellipses with
   layer blur — 0.3 @ 547×434 σ100 centre-left, 0.6 @ 644×405 σ164 lapping the
   right edge. Gradient extent = radius + 2σ; plateau stop ≈ radius − 2σ.
   Positions are container-relative (offset from centre) so they track content. */
.section--glow-both::before {
	background-image:
		radial-gradient(747px 634px at calc(50% - 105px) calc(55% - 51px), rgba(216,244,160,0.3) 46%, rgba(216,244,160,0) 100%),
		radial-gradient(973px 733px at calc(50% + 786px) calc(83% - 338px), rgba(216,244,160,0.6) 32%, rgba(216,244,160,0) 100%);
}
.text-muted { color: var(--c-text-muted); }

.section-head {
	display: flex; justify-content: space-between; align-items: flex-end;
	gap: var(--gap-lg); flex-wrap: wrap;
}
.section-head__body { max-width: 623px; font-size: var(--fs-body); color: var(--c-text-muted); }
.section-head__aside { display: flex; flex-direction: column; align-items: flex-start; gap: 20px; max-width: 623px; }
.deals__note { margin-top: 40px; max-width: 720px; font-size: var(--fs-body); color: var(--c-text-muted); }
.deals__note a { text-decoration: underline; }
.h2 { font-size: var(--fs-h2); }
/* Even out headline line lengths. Without this a heading whose text just
   overflows its column strands a short orphan line (the neighborhoods
   "Cannabis and Food Pairings, the San Francisco Way" left "Pairings," alone).
   Ignored by browsers without support, and it never overrides a hard <br>. */
.h2, .h2--2line, .nbh-hero__title, .hero__title, .band__title, .panel__title { text-wrap: balance; }
.h2--2line { font-size: var(--fs-h2-2line); }
.eyebrow { font-weight: var(--fw-medium); font-size: var(--fs-14); }

/* --- Buttons ------------------------------------------------------------ */
.btn {
	display: inline-flex; align-items: center; gap: var(--gap-xs);
	padding: 16px 32px; border-radius: var(--r-pill);
	font-weight: var(--fw-medium); font-size: var(--fs-body); line-height: 1;
	border: 1px solid var(--c-border); background: var(--c-white); color: var(--c-black);
	transition: transform .15s ease, opacity .15s ease;
}
.btn:hover { transform: translateY(-1px); opacity: .92; }
.btn--primary { background: var(--c-black); color: var(--c-white); }
.btn--ghost { background: var(--c-glass); color: var(--c-white); border-color: transparent; }
.btn .icon { width: 24px; height: 24px; }
.btn--sm { padding: 16px 24px; }

.icon-arrow { display: inline-block; width: 20px; height: 20px; }

/* ---- Interactive hover feedback (site-wide) ---------------------------- */
.pcard, .pcard-mini, .tile, .meadow-product-item {
	transition: transform .18s ease, box-shadow .18s ease;
}
.pcard:hover, .pcard-mini:hover, .tile--img:hover, .tile--brand:hover, .meadow-product-item:hover {
	transform: translateY(-4px); box-shadow: 0 14px 30px rgba(0,0,0,.12);
}
.chevron { transition: background .18s ease, color .18s ease, transform .18s ease; }
.chevron:hover { transform: scale(1.07); }
.chevron.is-disabled { opacity: .35; pointer-events: none; }
.pcard-mini__add, .meadow-product-thumbnail .meadow-add-to-cart-btn {
	transition: transform .15s ease, background .15s ease, box-shadow .15s ease;
}
.pcard-mini__add:hover, .meadow-product-thumbnail .meadow-add-to-cart-btn:hover {
	transform: scale(1.12); background-color: var(--c-green-mid);
}
.site-header__search-btn, .site-header__location { transition: transform .15s ease, background .18s ease; }
.site-header__search-btn:hover { transform: translateY(-1px); background: var(--c-green-light); }
.site-header__location:hover { transform: translateY(-1px); background: var(--c-green-light); }
/* Nav hover: animated brand-green underline sliding in from the left,
   plus a subtle lift (Shawn: "better hover effects"). */
.site-header__nav a { position: relative; padding-bottom: 4px; transition: color .18s ease; }
.site-header__nav a::after {
	content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
	border-radius: 1px; background: var(--c-green-mid);
	transform: scaleX(0); transform-origin: left center;
	transition: transform .22s cubic-bezier(.2,.6,.2,1);
}
.site-header__nav a:hover::after, .site-header__nav a:focus-visible::after { transform: scaleX(1); }
.site-footer__col a:hover { opacity: .6; }
.site-footer__col a { transition: opacity .15s ease; }
.faq__toggle { transition: background .15s ease, transform .15s ease; }
.faq__item:hover .faq__toggle { transform: scale(1.06); }
.meadow-product-view-btn, .sort-select, .lb_prod_filter_attr_title { transition: opacity .15s ease, transform .15s ease, background .15s ease; }
.meadow-product-view-btn:hover { transform: translateY(-1px); opacity: .92; }
.pcard-mini__name:hover, .pcard-mini__media:hover ~ .pcard-mini__name { text-decoration: underline; }
/* Mini-card image link keeps a clickable area even without an image. */
.pcard-mini__media { display: block; position: relative; z-index: 1; min-height: 143px; }

/* --- Header ------------------------------------------------------------- */
/* Fixed (not sticky) so it overlays content exactly like the old absolute
   header — no layout shift for the hero's padding math. JS toggles .is-stuck
   past 8px of scroll: the inner bar floats off the edges and condenses into a
   frosted full-radius pill. */
.site-header {
	position: fixed; top: 0; left: 0; right: 0; z-index: 50;
	transition: padding .25s ease;
}
.site-header.is-stuck { padding: 12px 16px 0; }
.site-header.is-stuck .site-header__inner {
	/* Glass (Shawn): mostly-transparent white + heavy blur/saturate so the
	   page reads through the pill; hairline border sells the pane edge. */
	background-color: rgba(255, 255, 255, 0.45);
	-webkit-backdrop-filter: blur(16px) saturate(1.6);
	backdrop-filter: blur(16px) saturate(1.6);
	border: 1px solid rgba(255, 255, 255, 0.55);
	box-shadow: 0 6px 24px rgba(0, 0, 0, 0.08);
	padding-block: 12px;
}
/* Keep the fixed/absolute header clear of the WP admin bar when logged in. */
body.admin-bar .site-header { top: 32px; }
@media (max-width: 782px) { body.admin-bar .site-header { top: 46px; } }
.site-header__inner {
	display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
	gap: var(--gap-md); padding-block: 24px; padding-inline: 32px;
	/* Fixed-width page: header content tracks the container cap. */
	max-width: var(--container); margin-inline: auto;
	/* Radius always on (invisible while transparent) so the stuck pill never
	   animates its corners. */
	border-radius: var(--r-pill);
	transition: background-color .25s ease, box-shadow .25s ease, padding .25s ease;
}
.site-header__nav { justify-self: start; min-width: 0; }
.site-header__nav .primary-menu { display: flex; gap: 32px; }
.site-header__nav a { font-weight: var(--fw-medium); font-size: var(--fs-14); }
.site-header__logo { justify-self: center; }
.site-logo--text { font-weight: var(--fw-medium); font-size: 22px; letter-spacing: .04em; text-transform: uppercase; }
.custom-logo, .site-logo img { height: 32px; width: auto; display: block; }

.site-header__actions { justify-self: end; display: flex; align-items: center; gap: var(--gap-xs); min-width: 0; }
.site-header__search-btn {
	width: 48px; height: 48px; border-radius: var(--r-pill); flex: 0 0 auto;
	background: var(--c-green-mid); color: var(--c-black); border: none;
	display: grid; place-items: center; cursor: pointer;
}
.site-header__search-btn .icon { width: 24px; height: 24px; }
.site-header__location {
	display: inline-flex; align-items: center; gap: 8px; height: 48px; padding: 0 20px; min-width: 0;
	/* Same fill as the search + cart circles — it was a 50% tint, so it read lighter. */
	border-radius: var(--r-pill); background: var(--c-green-mid); color: var(--c-black);
	font-weight: var(--fw-medium); font-size: var(--fs-14); white-space: nowrap;
}
.site-header__location .icon { width: 24px; height: 24px; flex: 0 0 auto; }
.site-header__sep { margin: 0 2px; }
.site-header__cart { display: flex; align-items: center; font-size: 22px; cursor: pointer; }
.site-header__cart.is-empty { display: none; }
.meadow-cart-count {
	display: inline-grid; place-items: center; min-width: 18px; height: 18px; padding: 0 4px;
	border-radius: 9px; background: #d23; color: #fff; font-size: 11px; font-weight: var(--fw-medium);
	vertical-align: top; margin-left: -6px;
}
.site-header__toggle { display: none; }
/* Search panel: frosted drop-down card with a magnifier inside the field —
   slides/fades open (Shawn: "more intuitive/nicer"). JS focuses the input. */
.site-header__search-panel { padding: 8px 16px 20px; }
.site-header__search-panel .search-form {
	display: flex; gap: 8px; align-items: center; max-width: 640px; margin-inline: auto;
	background: rgba(255, 255, 255, .75);
	-webkit-backdrop-filter: blur(16px) saturate(1.4);
	backdrop-filter: blur(16px) saturate(1.4);
	border: 1px solid rgba(255, 255, 255, .55); border-radius: var(--r-pill);
	padding: 8px; box-shadow: 0 12px 32px rgba(0, 0, 0, .1);
	animation: kush-search-in .22s cubic-bezier(.2,.6,.2,1);
}
@keyframes kush-search-in {
	from { opacity: 0; transform: translateY(-8px); }
	to   { opacity: 1; transform: none; }
}
/* The input sits inside get_search_form()'s <label> — stretch the label, fill the input. */
.site-header__search-panel .search-form label { flex: 1; display: block; min-width: 0; position: relative; }
.site-header__search-panel .search-form label::before {
	content: ""; position: absolute; left: 18px; top: 50%; translate: 0 -50%;
	width: 18px; height: 18px; pointer-events: none; opacity: .45;
	background: currentColor;
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M21 21l-4.35-4.35M17 10.5a6.5 6.5 0 1 1-13 0 6.5 6.5 0 0 1 13 0z' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M21 21l-4.35-4.35M17 10.5a6.5 6.5 0 1 1-13 0 6.5 6.5 0 0 1 13 0z' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
}
/* Triple selector: the generic results-page `.search-form .search-field`
   rule sits LATER in the file at equal specificity and would win. */
.site-header__search-panel .search-form .search-field {
	width: 100%; height: 48px; padding: 0 20px 0 46px; border-radius: var(--r-pill);
	border: 1px solid transparent; background: var(--c-grey-light); font-family: inherit; font-size: var(--fs-body);
	transition: border-color .15s ease, background .15s ease;
}
.site-header__search-panel .search-form .search-field:focus { background: var(--c-white); }
.site-header__search-panel .search-form .search-field::placeholder { color: var(--c-text-placeholder); }
.site-header__search-panel .search-submit {
	height: 48px; padding: 0 28px; border-radius: var(--r-pill); border: none; background: var(--c-black); color: #fff;
	font-family: inherit; font-weight: var(--fw-medium); cursor: pointer;
	transition: transform .15s ease, opacity .15s ease;
}
.site-header__search-panel .search-submit:hover { transform: translateY(-1px); opacity: .92; }

/* --- Focus rings: brand green, not the UA blue (Shawn) ------------------- */
input:focus-visible, textarea:focus-visible, select:focus-visible, button:focus-visible,
.field:focus, .search-field:focus,
.gform_wrapper input:focus, .gform_wrapper textarea:focus {
	outline: 2px solid var(--c-green-mid) !important;
	outline-offset: 1px;
	box-shadow: none;
}
a:focus-visible { outline: 2px solid var(--c-green-mid); outline-offset: 2px; border-radius: 2px; }

/* --- Invalid fields ------------------------------------------------------
   Gravity Forms marks a failure with .gfield_error on the wrapper and
   aria-invalid="true" on the control, but every themed input below sets
   `border: none !important`, so a failed field looked identical to a valid one
   — the only cue was the message text. The wrapper class is doubled to
   out-specify those (0,3,1) !important borders wherever they live
   (.panel / .site-footer__form / .contact__form); same trick as the search
   field's triple selector above. */
.gform_wrapper .gfield_error.gfield_error input:not([type=submit]),
.gform_wrapper .gfield_error.gfield_error textarea,
.gform_wrapper .gfield_error.gfield_error select,
input[aria-invalid="true"], textarea[aria-invalid="true"], select[aria-invalid="true"] {
	border: 2px solid var(--c-error) !important;
}
/* The green focus ring above is !important, so the error ring has to be too —
   otherwise focusing a failed field repaints it green. */
.gform_wrapper .gfield_error.gfield_error input:not([type=submit]):focus,
.gform_wrapper .gfield_error.gfield_error textarea:focus,
.gform_wrapper .gfield_error.gfield_error select:focus,
input[aria-invalid="true"]:focus, textarea[aria-invalid="true"]:focus, select[aria-invalid="true"]:focus {
	outline: 2px solid var(--c-error) !important;
	outline-offset: 1px;
	box-shadow: 0 0 0 4px var(--c-error-ring) !important;
}

/* --- Hero --------------------------------------------------------------- */
.hero {
	position: relative; overflow: hidden;
	display: flex; flex-direction: column; justify-content: flex-start;
	min-height: 100vh; min-height: 100svh;
	/* Figma 20220:333: 96px header + 447px gap → title starts 543px from the top. */
	padding-top: 543px; padding-bottom: 48px;
	background: var(--c-white);
	text-align: left;
}
/* Hero scene = Figma frame 3 (20208:192), reproduced EXACTLY: layers use the
   frame's own 1440×1024 pixel geometry inside a canvas that cover-scales to
   the viewport, so the composition keeps the frame's proportions on any
   screen (vw-based sizing distorted badly on wide monitors). */
.hero__scene { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; background: #fff; }
.hero__scene-canvas {
	/* cover: scale by whichever axis needs more; 140.63vh = 100vh · (1440/1024).
	   Length ÷ length → unitless number (CSS Values 4). */
	--scene-scale: calc(max(100vw, 140.63vh) / 1440px);
	position: absolute; top: 0; left: calc(50% - 720px * var(--scene-scale));
	width: 1440px; height: 1024px;
	transform: scale(var(--scene-scale)); transform-origin: top left;
	overflow: hidden; /* clip layers at the frame edge, like the Figma frame */
	/* Backdrop = the photo's own baked-in sky colours (sampled), so when the
	   bridge is drawn smaller (short-wide windows) the exposed areas match the
	   photo instead of showing a second, brighter green. Invisible at normal
	   aspect where the photo covers the whole canvas. */
	background: linear-gradient(180deg, #b4d491 0%, #c0cf9d 24%, #cdc3a4 41%, #ffffff 62%);
}
/* Figma node geometry (px in the 1440×1024 frame) */
.hero__scene-bridge {
	position: absolute; left: -209px; top: -137px; width: 2072px; height: 1381px;
	background: url(../img/prepage-bridge.webp) center / cover no-repeat;
}
.hero__scene-grads {
	position: absolute; left: -376px; top: -155px; width: 2320px; height: 1547px;
	background:
		linear-gradient(180deg, rgba(255,255,255,0) 38.3%, #ffffff 75.4%),
		linear-gradient(180deg, #d8f4a0 9.76%, rgba(216,244,160,0) 61.97%);
}
/* Figma layer 20208:196 — the bridge painted AGAIN above the washes: this is
   what keeps the tower vivid through the fog. The repaint fades OUT (mask)
   instead of fading TO white — painting to white laid an opaque white sheet
   behind the clouds across the lower half of the scene. */
.hero__scene-bridge2 {
	position: absolute; left: -209px; top: -137px; width: 2072px; height: 1381px;
	background: url(../img/prepage-bridge.webp) center / cover no-repeat;
	-webkit-mask-image: linear-gradient(180deg, #000 31.1%, transparent 49.1%);
	mask-image: linear-gradient(180deg, #000 31.1%, transparent 49.1%);
}
/* Short/wide windows: the width-driven cover scale crops the frame hard
   vertically, blowing the bridge up. Zoom the bridge out beyond width
   coverage: draw it smaller, centred, nudged down so the tower top stays in
   frame, sides fading into the green sky gradient behind it.
   MUST come AFTER the base .hero__scene-bridge2 rule: same specificity, so
   file order decides — when this block sat above it, the base rule's
   mask/background silently killed the whole branch (the "colour separation
   is back" regression). */
@media (min-aspect-ratio: 8/5) {
	.hero__scene-bridge, .hero__scene-bridge2 {
		transform: translateY(170px) scale(.55); transform-origin: 38.5% 0;
		/* fade sides, top AND bottom so the photo's edges never print hard
		   bands: the untinted lower photo — city skyline, water — otherwise
		   shows through as a second colour band. Bottom fade hits ZERO by 43%,
		   before the photo's dark hill silhouette (~el 47%). */
		-webkit-mask-image: linear-gradient(90deg, transparent 0, #000 14%, #000 86%, transparent 100%), linear-gradient(180deg, transparent 0, #000 18%), linear-gradient(180deg, #000 31.1%, transparent 43%);
		-webkit-mask-composite: source-in;
		mask-image: linear-gradient(90deg, transparent 0, #000 14%, #000 86%, transparent 100%), linear-gradient(180deg, transparent 0, #000 18%), linear-gradient(180deg, #000 31.1%, transparent 43%);
		mask-composite: intersect;
	}
	/* bridge2's vivid repaint is confined to the TOWER COLUMN (centre ≈ layer
	   x 48.5%): bridge1 blends seamlessly with the wash that paints over it,
	   so the less untinted repaint that shows, the less the photo's grey sky
	   can split from the bright wash (the vertical boundary at the photo's
	   left/right edges). Its sky is tinted with the wash colour on top. */
	.hero__scene-bridge2 {
		/* tint dies by 45% — deeper plateaus turn the tower olive */
		background:
			linear-gradient(180deg, rgba(216,244,160,.85) 0, rgba(216,244,160,0) 45%),
			url(../img/prepage-bridge.webp) center / cover no-repeat;
		-webkit-mask-image: linear-gradient(90deg, transparent 30%, #000 42%, #000 55%, transparent 67%), linear-gradient(180deg, transparent 0, #000 18%), linear-gradient(180deg, #000 31.1%, transparent 49.1%);
		-webkit-mask-composite: source-in;
		mask-image: linear-gradient(90deg, transparent 30%, #000 42%, #000 55%, transparent 67%), linear-gradient(180deg, transparent 0, #000 18%), linear-gradient(180deg, #000 31.1%, transparent 49.1%);
		mask-composite: intersect;
	}
}
/* Animated scene video. Desktop geometry mirrors the 1440×1024 canvas
   cover-scale so the animated frame lands exactly on the static layers it
   fades over; the ≤900px block swaps in the mobile geometry.
   The two clips differ, so the wordmark rules below are breakpoint-scoped:
   DESKTOP's clip has NO wordmark (scene only) — the theme wordmark is the only
   one there and must stay. MOBILE's still bakes one in, so the theme wordmark
   hands over to it. */
.hero__scene-video {
	--vscale: calc(max(100vw, 140.63vh) / 1440px);
	position: absolute; top: 0; left: calc(50% - 720px * var(--vscale));
	width: calc(1440px * var(--vscale)); height: calc(1024px * var(--vscale));
	object-fit: cover; opacity: 0; pointer-events: none;
	/* Short: on desktop the scene underneath IS this clip's frame 0 (see
	   .hero__scene-plate), so there is nothing to reveal — measured ~0.5% of
	   pixels differing, i.e. webp noise. The brief fade only covers the residual
	   and the ≤900px case, where the plate is off and the clip is other art. */
	transition: opacity .25s linear;
}
.hero__scene-video.is-playing { opacity: 1; }
/* Both clips are scene-only now, so the theme wordmark is the ONLY wordmark at
   every breakpoint and simply stays put through the hand-off — nothing hides it,
   and only the scene beneath it changes. (Until 2026-07-17 the clips baked their
   own wordmark in, which forced a hide-and-hand-over here.) */

/* Wordmark sits OUTSIDE the canvas: it scales to the VIEWPORT (Figma fraction
   85.4% width, centre 25.4% height, capped by height) so it keeps the frame's
   proportions even on short/wide windows where the cover-scaled canvas crops
   vertically and would balloon it. */
.hero__scene-wordmark {
	position: absolute; left: 50%; top: 25.4vh; transform: translate(-50%, -50%);
	width: min(85.4vw, 120vh); aspect-ratio: 1230 / 284.45;
	background: #fff; opacity: 1;
	-webkit-mask: url(../img/prepage-wordmark.png) center / contain no-repeat;
	mask: url(../img/prepage-wordmark.png) center / contain no-repeat;
}
/* The hero video's own frame 0, per breakpoint, as the static scene. It fills
   the same canvas box the video's element covers (verified both ≥901px and
   ≤900px), so the two register exactly and the hand-off reveals nothing.
   The gate has no scene of its own — the hero shows through it — so this is the
   flight's backdrop too, and both ends of the hand-off match by construction. */
.hero__scene-plate { position: absolute; inset: 0; background: center / cover no-repeat; }
@media (min-width: 901px) { .hero__scene-plate { background-image: url(../img/hero-scene-desktop.webp); } }
@media (max-width: 900px) { .hero__scene-plate { background-image: url(../img/hero-scene-mobile.webp); } }
/* The fog is baked into both plates now. The element STAYS: the age-gate flight
   measures it to aim the fog landing and the content rise (see runTransition). */
.hero__scene-clouds { visibility: hidden; }

.hero__scene-clouds {
	position: absolute; left: -240px; top: 55px; width: 1920px; height: 766px;
	background: url(../img/prepage-fog.png) center top / 100% 100% no-repeat;
	/* Same drift as the footer clouds; 240px canvas-space overhang per side
	   keeps the ±60px sweep from exposing an edge. */
	will-change: transform;
	animation: kush-clouds-drift-plain 7s ease-in-out infinite alternate;
}
@keyframes kush-clouds-drift-plain {
	from { transform: translateX(-60px); }
	to   { transform: translateX(60px); }
}
@media (prefers-reduced-motion: reduce) {
	.hero__scene-clouds { animation: none; }
}
/* Below the canvas the scene stays white (canvas bottom fades to white). */
.hero__scene-canvas::after {
	content: ""; position: absolute; left: -376px; width: 2320px; top: 1023px; height: 1200px;
	background: #fff;
}
/* Fade the scene into pure white at the hero's bottom edge so there is no
   seam against the sections that follow (the fog image's bottom pixels are
   warm grey, not #fff), and continue the categories glow upward — its z:-1
   pseudo can't paint over the hero, so its tint would otherwise cut off
   exactly at the boundary. The radial mirrors .section--glow-categories
   (centre 277px below the hero bottom, 455px right of centre); the 400px box
   gives the ellipse its full 357px reach into the hero, and the white fade
   stays anchored to the bottom 28vh as before. */
.hero__scene::after {
	content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 400px;
	background:
		radial-gradient(747px 634px at calc(50% + 455px) calc(100% + 277px), rgba(216,244,160,0.3) 46%, rgba(216,244,160,0) 100%),
		linear-gradient(180deg, rgba(255,255,255,0) calc(100% - 28vh), #ffffff calc(100% - 7.84vh));
}
.hero__inner {
	position: relative; z-index: 2; display: flex; justify-content: space-between;
	align-items: flex-end; gap: var(--gap-lg); flex-wrap: wrap;
}
.hero__intro { max-width: 760px; }
.hero__title { font-size: var(--fs-h1); }
.hero__subtitle { font-size: var(--fs-body); color: var(--c-text-muted); margin-top: 12px; max-width: 560px; }
.hero__actions { display: flex; gap: var(--gap-xs); flex-wrap: wrap; }
/* Product carousel sits in FRONT of the hero wash, grouped just below the heading.
   Full-bleed: the scroller spans the viewport and cards clip at both edges (Figma),
   while the first card still lines up with the container/title edge. */
.hero__carousel { position: relative; z-index: 3; margin-top: 40px; width: 100%; }
/* (the hero scroller uses .hscroll--bleed for its inset, same as the sections) */

/* Drag-to-scroll (mouse) for carousels; snap pauses while dragging. */
.hscroll { cursor: grab; }
.hscroll.is-dragging { cursor: grabbing; scroll-snap-type: none; user-select: none; }
.hscroll.is-dragging a, .hscroll.is-dragging img { pointer-events: none; }

/* Full-bleed carousel: the scroller breaks out to span the viewport; the first
   card lines up with the container edge and cards clip at the SCREEN edges.
   The inset is a first-child margin + ::after spacer, NOT padding — scroll
   containers clip content at the content box, so a padded inset hides cards
   mid-scroll instead of letting them bleed. */
.hscroll.hscroll--bleed { /* double class: must beat the .hscroll margin shorthand below */
	--bleed-inset: max(var(--container-pad), calc((100vw - var(--container)) / 2 + var(--container-pad)));
	width: 100vw;
	margin-left: calc(50% - 50vw);
	scroll-padding-inline: var(--bleed-inset);
}
.hscroll--bleed > :first-child { margin-left: var(--bleed-inset); }
/* End spacer (the flex gap contributes var(--gap-md) of the inset). */
.hscroll--bleed::after { content: ""; flex: 0 0 calc(var(--bleed-inset) - var(--gap-md)); }

/* Hero mini product cards */
.pcard-mini {
	flex: 0 0 240px; width: 240px; min-height: 280px;
	background: var(--c-green-light); border-radius: var(--r-card);
	padding: 20px; position: relative; text-align: left;
	display: flex; flex-direction: column; gap: 8px;
}
.pcard-mini__img { width: 143px; height: 143px; object-fit: contain; margin: 8px auto 16px; }
.pcard-mini__name { font-weight: var(--fw-medium); font-size: var(--fs-body); }
.pcard-mini__meta { display: flex; align-items: center; gap: 8px; font-size: var(--fs-12); color: var(--c-text-muted); }
.pcard-mini__meta .dot { width: 3px; height: 3px; border-radius: 50%; background: currentColor; }
.pcard-mini__add {
	position: absolute; top: 16px; right: 16px; z-index: 4; width: 34px; height: 34px;
	border-radius: var(--r-pill); border: 1px solid var(--c-border); background: var(--c-white);
	box-shadow: 0 2px 8px rgba(20, 46, 22, 0.16);
	display: grid; place-items: center; padding: 0;
	font-weight: var(--fw-regular); line-height: 1; color: var(--c-black);
	/* Same fix as .product-card__add: the Meadow plugin overwrites this button's
	   textContent to "Adding…/Added" on click, which at 22px ballooned inside the
	   circle. Zero the font + clip; draw the + as a centred SVG bg (see .product-card__add). */
	font-size: 0; overflow: hidden;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14'%3E%3Cpath d='M7 1.5v11M1.5 7h11' stroke='%23111' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat; background-position: center; background-size: 14px 14px;
}
.pcard-mini__add::before { content: none; }
.pcard-mini__add:disabled { opacity: .55; cursor: default; transform: none; }

/* Horizontal scroller (used by carousels for now).
   overflow-y must be explicit: leaving it unset makes it compute to auto
   alongside overflow-x, so the row could also scroll vertically. Block
   padding + negative margins keep hover lift/shadows visible inside the
   clip without changing the row's footprint. */
.hscroll {
	display: flex; gap: var(--gap-md);
	overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
	scroll-snap-type: x mandatory;
	padding: 12px 0 52px; margin: -12px 0 -44px;
	-ms-overflow-style: none; scrollbar-width: none;
}
.hscroll::-webkit-scrollbar { display: none; }
.hscroll > * { scroll-snap-align: start; }

/* Carousel controls */
.carousel-controls { display: flex; justify-content: space-between; align-items: center; margin-top: 24px; }
/* Interactive scrollbar: visual band stays 2px (content-box), the padding
   gives a 16px grab/click target. Scrubbing is wired in main.js. */
.progressbar {
	width: 256px; height: 16px; padding-block: 7px;
	background: var(--c-divider); background-clip: content-box;
	border-radius: var(--r-card-sm); overflow: hidden;
	cursor: pointer; touch-action: none;
}
/* display:block — the fill is a <span>; inline boxes ignore width/height. */
.progressbar__fill { display: block; width: 40%; height: 100%; background: var(--c-black); transition: transform .25s ease; will-change: transform; }
.progressbar.is-scrubbing .progressbar__fill { transition: none; }
.chevrons { display: flex; gap: var(--gap-xs); }
.chevron {
	width: 48px; height: 48px; border-radius: var(--r-pill); background: transparent;
	border: 1px solid var(--c-border-strong); display: grid; place-items: center;
}
.chevron--active { background: var(--c-near-black); color: var(--c-white); border-color: var(--c-border); }

/* --- Category / discount / location cards ------------------------------- */
.card-row { display: flex; gap: var(--gap-md); }
.tile {
	position: relative; overflow: hidden; border-radius: var(--r-card);
	background: var(--c-green-light-50); padding: 32px;
	display: flex; flex-direction: column; justify-content: flex-end;
	color: var(--c-white); min-height: 320px;
}
.tile--img::after {
	content: ""; position: absolute; inset: 0; z-index: 1;
	background: var(--overlay-img);
}
.tile__bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.tile__title { position: relative; z-index: 2; font-weight: var(--fw-medium); font-size: var(--fs-22); }
.tile--category .tile__title { font-size: var(--fs-card-title); }
.tile__body { position: relative; z-index: 2; font-size: var(--fs-body); }
.tile--text { color: var(--c-text); justify-content: flex-start; }
.tile--text .tile__title { font-size: var(--fs-20); color: var(--c-text); }
.tile--text .tile__body { color: var(--c-text-muted); margin-top: 12px; }
.tile--category { flex: 0 0 480px; width: 480px; }
.tile--location { flex: 0 0 400px; width: 400px; min-height: 504px; }
.tile--location .tile__body { color: var(--c-text-on-dark-muted); margin-top: 12px; }

/* Branded fallback tile (no photo yet) — on-brand green, dark text, wordmark watermark */
.tile--brand {
	background: linear-gradient(150deg, var(--c-green-light), var(--c-green-deep-50));
	color: var(--c-text);
}
.tile--brand::before {
	content: "KUSHOLOGY"; position: absolute; inset: 0; z-index: 0; display: grid; place-items: center;
	font-weight: var(--fw-medium); letter-spacing: .1em; font-size: 16px; color: rgba(0,0,0,.1); pointer-events: none;
}
.tile--brand .tile__title { color: var(--c-text); position: relative; z-index: 2; }
.tile--brand .tile__body { color: var(--c-text-muted); position: relative; z-index: 2; margin-top: 12px; }

/* --- Featured products grid --------------------------------------------- */
.featured { text-align: center; }
.featured__grid {
	display: grid; grid-template-columns: repeat(6, minmax(0,1fr)); gap: 80px var(--gap-md);
	margin: 72px 0;
}
.pcard {
	position: relative; aspect-ratio: 1 / 1; border-radius: var(--r-card-sm);
	background: linear-gradient(to bottom, var(--c-green-light) 48%, var(--c-green-deep-50) 100%);
	display: grid; place-items: center; padding: 16px; overflow: hidden;
}
/* KUSHOLOGY backdrop watermark for image tiles. NOT on .product-single__media:
   the detail image is large and object-fit:contain (or a transparent fallback),
   so the centred watermark bled through as a stray "KUSHOLOGY". The detail page
   always has a real or fallback image, so it needs no backdrop. */
.pcard::before, .meadow-product-thumbnail::before, .pcard-mini::after {
	content: "KUSHOLOGY"; position: absolute; inset: 0; z-index: 0;
	display: grid; place-items: center; text-align: center;
	font-weight: var(--fw-medium); font-size: 13px; letter-spacing: .12em;
	color: rgba(0,0,0,.16); pointer-events: none;
}
.pcard-mini::after { inset: 24px 20px auto; height: 143px; }
/* Drop the watermark once the photo has actually painted. It's the placeholder
   for a tile with no image yet, but .pcard__img uses mix-blend-mode: multiply —
   which makes the photo's white areas transparent — so on light-heavy shots the
   word showed THROUGH the product and read as text printed across it.
   Keyed on .is-loaded (set in main.js), NOT on the mere presence of an <img>:
   these are loading="lazy", so the element exists long before it renders and a
   presence check would blank the tile for the whole load. */
.pcard:has(.pcard__img.is-loaded)::before,
.meadow-product-thumbnail:has(img.is-loaded)::before,
.pcard-mini:has(.pcard-mini__img.is-loaded)::after { content: none; }
.pcard__img, .meadow-product-thumbnail img, .product-single__media img, .pcard-mini__img { position: relative; z-index: 1; }
/* Meadow photos are JPEGs on white — multiply drops the white rectangle so
   products sit directly on the green tile like Figma's transparent renders
   (20210:670). White inside the packaging picks up a slight green cast:
   inherent to the trick, invisible at tile size. */
.pcard__img { width: 80%; height: 80%; object-fit: contain; mix-blend-mode: multiply; }
.pcard__tag {
	position: absolute; top: 8px; right: 8px; z-index: 2;
	display: inline-flex; align-items: center; height: 28px;
	background: var(--c-chip-overlay); color: var(--c-white);
	font-weight: var(--fw-medium); font-size: var(--fs-10);
	padding: 0 8px; border-radius: var(--r-card-sm);
}

.recommend__img { display: block; max-width: 860px; width: 100%; height: auto; margin: 0 auto 40px; }

/* --- About statement band ----------------------------------------------- */
.band {
	position: relative; overflow: hidden; border-radius: var(--r-panel);
	min-height: 800px; padding: 80px 48px;
	/* Fixed-width page: 16px side gaps up to the container cap, then centred. */
	width: min(100% - 32px, calc(var(--container) - 32px)); margin-inline: auto;
	display: flex; flex-direction: column; align-items: center; justify-content: center;
	gap: var(--gap-lg); text-align: center; color: var(--c-white);
	background: #333;
}
.band__bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.band::after {
	content: ""; position: absolute; inset: 0; z-index: 1;
	background:
		linear-gradient(180deg, rgba(0,0,0,0) 19.8%, rgba(0,0,0,0.64) 58.7%, rgba(0,0,0,0.8) 97.7%),
		linear-gradient(178deg, rgba(0,0,0,0.6) 2.7%, rgba(0,0,0,0) 41.1%),
		linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4));
}
/* text-shadow as well as the ::after scrim: the storefront photo has a large lit
   sign behind this copy, and darkening the overlay enough to beat it flattens the
   whole image. The shadow only costs contrast where the glyphs actually are. */
.band__title { position: relative; z-index: 2; font-size: var(--fs-statement); max-width: 880px;
	text-shadow: 0 1px 3px rgba(0,0,0,.55), 0 0 18px rgba(0,0,0,.4); }
.band__actions { position: relative; z-index: 2; display: flex; gap: var(--gap-xs); flex-wrap: wrap; justify-content: center; }

/* --- Panels (newsletter / footer) --------------------------------------- */
.panel {
	background: var(--c-green-light); border-radius: var(--r-panel);
	padding: 80px 56px;
	/* Fixed-width page: 16px side gaps up to the container cap, then centred. */
	width: min(100% - 32px, calc(var(--container) - 32px)); margin-inline: auto;
}
/* Figma 20230:230 — full-width head (gap 16) above image | form card (gap 24). */
.panel--newsletter { display: flex; flex-direction: column; gap: 48px; }
/* Jump target for the footer's "Sign Up" link on pages that already embed the
   form. Header clearance now comes from the global html{scroll-padding-top}. */
.panel__head { display: flex; flex-direction: column; gap: 16px; }
.panel__row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-md); align-items: stretch; }
.panel__media { border-radius: var(--r-card); overflow: hidden; }
.panel__media img { width: 100%; height: 100%; object-fit: cover; }
.panel__title { font-size: var(--fs-h2-2line); }
.panel__body { font-size: var(--fs-body); color: var(--c-text-muted); }

/* Forms */
.signup { background: var(--c-white); border-radius: var(--r-panel); padding: 24px; height: 100%; display: flex; flex-direction: column; justify-content: center; gap: 32px; }
.signup__fields { display: flex; flex-direction: column; gap: var(--gap-sm); }
.signup__divider { width: 100%; margin: 0; border: none; border-top: 1px solid var(--c-divider); }
.signup__footer { display: flex; flex-direction: column; gap: 24px; }
.signup__row { display: flex; gap: var(--gap-sm); }
.signup__row > * { flex: 1; }
.field {
	width: 100%; height: 56px; padding: 16px 24px; border-radius: var(--r-pill);
	border: none; background: var(--c-grey-light); font-family: inherit;
	font-weight: var(--fw-medium); font-size: var(--fs-body); color: var(--c-text);
}
.field::placeholder { color: var(--c-text-placeholder); }
.signup .btn { justify-content: center; width: 100%; }
.legal { font-size: var(--fs-14); color: var(--c-text-muted); }
.legal a { text-decoration: underline; }

/* Homepage newsletter Gravity Form (light). The WHITE CARD is the form column
   (not the gform wrapper) so the theme legal below the button — Figma
   20228:817 — sits inside the card with it. */
.panel__form:has(.gform_wrapper) {
	background: var(--c-white); border-radius: var(--r-panel); padding: 24px;
	display: flex; flex-direction: column; justify-content: center; gap: 24px;
}
.panel .gform_wrapper { margin-top: 0; background: none; border-radius: 0; padding: 0; }
.panel .gform_fields { display: grid; grid-template-columns: 1fr 1fr; gap: 16px !important; list-style: none; margin: 0; padding: 0; }  /* !important: GF's theme sets its own larger row gap */
.panel .gfield { margin: 0; max-width: 100%; }
/* Figma 20228:817: First+Last share a row (they're sub-inputs of GF's single
   Name field); every other field — Phone, Email — runs full width, overriding
   the form's own gfield--width-half settings. */
.panel .gfield--width-full, .panel .gform_fields > .gfield,
.panel .gform_footer { grid-column: 1 / -1; }
/* The form's own consent HTML field duplicates the theme legal (which matches
   Figma and sits BELOW the button — see newsletter.php). Honeypot/validation
   utility fields otherwise hold EMPTY grid rows (uneven field gaps). */
.panel .gfield--type-html, .panel .gform_validation_container,
.panel .gfield--type-honeypot, .panel .gfield.gfield_visibility_hidden { display: none; }
/* Divider between fields and button (Figma: 32px each side; 16px grid gap +
   16px margin = 32). */
.panel .gform_footer { border-top: 1px solid var(--c-divider); margin-top: 16px; padding-top: 32px; }
.panel .gfield_label, .panel .gform_required_legend { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }
.panel .gform_wrapper input:not([type=submit]),
.panel .gform_wrapper .ginput_container input {
	width: 100% !important; height: 56px; padding: 16px 24px !important; border-radius: var(--r-pill) !important;
	border: none !important; background: var(--c-grey-light) !important; font-family: inherit; font-weight: var(--fw-medium);
	font-size: var(--fs-body); color: var(--c-text);
}
.panel .gform_wrapper input::placeholder { color: var(--c-text-placeholder); }
.panel .gform_wrapper .gform_footer input[type=submit],
.panel .gform_wrapper .gform_button {
	width: 100% !important; height: var(--btn-h); border-radius: var(--r-pill) !important; border: none !important;
	background: var(--c-black) !important; color: var(--c-white) !important; font-family: inherit;
	font-weight: var(--fw-medium); cursor: pointer;
}

/* --- FAQ ---------------------------------------------------------------- */
.faq { display: grid; grid-template-columns: 1fr 800px; gap: var(--gap-section); }
.faq__list { display: flex; flex-direction: column; }
.faq__item { border-top: 1px solid var(--c-divider); padding: 24px 0; }
.faq__q { cursor: pointer; list-style: none; }
.faq__q::-webkit-details-marker { display: none; }
.faq__item:first-child { border-top: none; }
.faq__q {
	display: flex; justify-content: space-between; align-items: center; gap: 16px;
	width: 100%; background: none; border: none; text-align: left; padding: 0;
	font-family: inherit; font-weight: var(--fw-medium); font-size: var(--fs-22); color: var(--c-text);
}
/* Questions are H3s for AEO parsers (checklist §4.3) — visually unchanged. */
.faq__q-text { font: inherit; margin: 0; }
.faq__toggle {
	flex: 0 0 40px; width: 40px; height: 40px; border-radius: var(--r-pill);
	border: 1px solid var(--c-border); background: transparent;
	display: grid; place-items: center; font-size: 20px; line-height: 1;
}
.faq__item[open] .faq__toggle { background: var(--c-white); }
.faq__a { margin-top: 16px; font-size: var(--fs-body); color: var(--c-text-muted); max-width: 720px; }
/* "+" spins away and crossfades into the "−" Figma shows on open items
   (a plain +/− swap was a hard cut; rotating + alone ends as "×"). */
.faq__q .plus, .faq__q .minus {
	grid-area: 1 / 1; display: block;
	transition: transform .35s cubic-bezier(.2,.6,.2,1), opacity .25s ease;
}
.faq__q .minus { opacity: 0; transform: rotate(-135deg); }
.faq__item[open] .faq__q .plus { opacity: 0; transform: rotate(135deg); }
.faq__item[open] .faq__q .minus { opacity: 1; transform: rotate(0deg); }
/* Smooth expand/collapse of the answer (interpolate-size lets height:auto animate;
   browsers without ::details-content support simply toggle instantly). */
html { interpolate-size: allow-keywords; }
.faq__item::details-content {
	opacity: 0; block-size: 0; overflow: clip;
	transition: content-visibility .35s allow-discrete, opacity .3s ease, block-size .35s cubic-bezier(.2,.6,.2,1);
}
.faq__item[open]::details-content { opacity: 1; block-size: auto; }

/* --- Footer ------------------------------------------------------------- */
.site-footer {
	/* Figma 20215:2179 — the footer is a rounded panel (24px), and overflow:hidden
	   is what makes the radius bite: the bleed layers inside it (bg photo, the
	   full-bleed wordmark, the cloud band) all clip to the curve instead of
	   running square off the corners. */
	position: relative; overflow: hidden; color: var(--c-text-on-dark);
	border-radius: var(--r-panel);
	padding: 88px 56px 0;
	background: #1a1d16 center/cover no-repeat;
}
.site-footer::before { content: ""; position: absolute; inset: 0; background: rgba(0,0,0,.7); z-index: 0; }
.site-footer__inner { position: relative; z-index: 2; }
.site-footer__top {
	/* Figma 20215:2287 — 460px signup + 136px gap, then the link columns. Four now:
	   the profile links were an unlabelled tail on "Visit Us" and ran into the
	   opening hours, so they became their own "Follow Us" column. The signup is
	   narrower to buy that column its width. */
	display: grid; grid-template-columns: minmax(0, 480px) 1fr 1fr 1fr 1fr; gap: 40px 24px;
}
.site-footer__signup { max-width: 460px; }
.site-footer__heading { font-size: var(--fs-h2-2line); margin-bottom: 16px; }
.site-footer__lede { color: var(--c-text-on-dark-muted); font-size: var(--fs-body); margin-bottom: 48px; max-width: 340px; }
.site-footer__col-title { font-size: var(--fs-20); margin-bottom: 16px; }
.site-footer__col ul { display: flex; flex-direction: column; gap: 16px; }
.site-footer__col a, .site-footer__visit li { color: var(--c-text-on-dark); font-size: var(--fs-14); line-height: var(--lh-body); }
.site-footer__col a:hover { text-decoration: underline; }
.site-footer__visit li { display: flex; align-items: center; gap: 8px; }
.site-footer__visit .icon { width: 16px; height: 16px; flex: none; }
.site-footer__terms { font-size: var(--fs-14); line-height: var(--lh-body); color: var(--c-text-on-dark-muted); margin-top: 24px; }
.site-footer__license {
	position: relative; z-index: 2; margin-top: 40px;
	font-size: var(--fs-12); color: var(--c-text-on-dark-muted); text-align: center;
}
.site-footer__terms a { color: inherit; text-decoration: underline; }
/* Figma 20215:2240 — full-bleed wordmark across the panel width.
   Paints the HEADER's logo art (logo.svg) through a mask rather than shipping a
   separate coloured export: same lettering as the header by construction, and the
   colour is a token, not baked-in pixels. #d8f4a0 is what the old raster's ink
   sampled to, so this is a like-for-like swap.
   aspect-ratio tracks logo.svg's own viewBox (139x32) — the mask is `contain`, so
   a mismatch would letterbox the glyphs inside the box rather than fill it. */
.site-footer__wordmark {
	position: relative; z-index: 1; margin: 120px -56px 0; user-select: none;
	aspect-ratio: 139 / 32;
	background: var(--c-green-light);
	-webkit-mask: url(../img/logo.svg) center / contain no-repeat;
	mask: url(../img/logo.svg) center / contain no-repeat;
}
.site-footer__clouds {
	/* Figma 20215:3321 — 1920x766 cloud band cropped at the panel's bottom edge. */
	position: absolute; left: 50%; bottom: -320px; transform: translateX(-50%);
	width: max(133%, 1920px); max-width: none; height: 766px; object-fit: cover; object-position: bottom;
	z-index: 2; pointer-events: none;
	/* object-fit's crop slices through cloud pixels — fade the top edge so the
	   horizontal cut line never shows. */
	-webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 200px);
	mask-image: linear-gradient(to bottom, transparent 0, #000 200px);
	/* Slow drift; 133% width keeps ≥16% overhang per side, so ±60px never
	   exposes an edge. Two copies at different speeds/directions read as depth. */
	will-change: transform;
	animation: kush-clouds-drift 7s ease-in-out infinite alternate;
}
.site-footer__clouds--back {
	animation: kush-clouds-drift-back 11s ease-in-out infinite alternate;
	opacity: .6;
}
@keyframes kush-clouds-drift {
	from { transform: translateX(calc(-50% - 60px)); }
	to   { transform: translateX(calc(-50% + 60px)); }
}
@keyframes kush-clouds-drift-back {
	from { transform: translateX(calc(-50% + 50px)) scale(1.08); }
	to   { transform: translateX(calc(-50% - 50px)) scale(1.08); }
}
@media (prefers-reduced-motion: reduce) {
	.site-footer__clouds { animation: none; }
	.site-footer__clouds--back { display: none; }
}

/* Footer Gravity Form (dark) */
/* !important: the GF "orbital" theme sets its own row-gap (40px) and footer
   margin (24px); Figma 20215:2273 wants 16px everywhere. */
.site-footer__form .gform_fields { display: grid; grid-template-columns: 1fr 1fr; gap: 16px !important; list-style: none; margin: 0; padding: 0; }
.site-footer__form .gfield { margin: 0; max-width: 100%; }
.site-footer__form .gfield--width-full, .site-footer__form .gform_footer { grid-column: 1 / -1; }
/* Hairline divider between the inputs and the Sign Up button (Figma 20215:2265). */
.site-footer__form .gform_footer { border-top: 1px solid var(--c-border); margin-top: 16px !important; padding-top: 16px !important; }
/* The form's own consent HTML field duplicates .site-footer__terms (which matches
   the Figma placement below the button) — suppress it. */
.site-footer__form .gfield--type-html { display: none; }
.site-footer__form .gform_wrapper input:not([type=submit]),
.site-footer__form .gform_wrapper .ginput_container input {
	width: 100% !important; height: 48px; padding: 12px 20px !important; border-radius: var(--r-pill) !important;
	border: none !important; background: var(--c-glass) !important; color: var(--c-text-on-dark) !important;
	font-family: inherit; font-size: var(--fs-14);
}
.site-footer__form .gform_wrapper input::placeholder { color: var(--c-text-on-dark-placeholder); }
.site-footer__form .gform_wrapper .gform_footer input[type=submit],
.site-footer__form .gform_wrapper .gform_button {
	width: 100% !important; height: 48px !important; border-radius: var(--r-pill) !important; border: none !important;
	background: var(--c-white) !important; color: var(--c-black) !important; font-family: inherit;
	font-weight: var(--fw-medium); font-size: var(--fs-14) !important; cursor: pointer;
	display: inline-flex; align-items: center; justify-content: center; gap: var(--gap-xs);
}
.gform_button .icon-arrow { width: 24px; height: 24px; flex: none; }
.site-footer__form .gfield_label, .site-footer__form .gform_required_legend { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }

@media (max-width: 900px) {
	.site-footer { padding: 56px 24px 0; }
	.site-footer__top { grid-template-columns: 1fr 1fr; gap: 32px; }
	.site-footer__signup { max-width: none; }
	.site-footer__wordmark { margin: 64px 0 0; }
	.site-footer__clouds { width: max(150%, 1000px); height: 400px; bottom: -170px; }
}
@media (max-width: 560px) {
	.site-footer__top { grid-template-columns: 1fr; }
	.site-footer__form .gform_fields { grid-template-columns: 1fr; }
}

/* ==========================================================================
   Cart drawer + checkout (styles the Meadow cart/checkout markup)
   ========================================================================== */
.kush-cart-backdrop {
	position: fixed; inset: 0; z-index: 9998; background: rgba(0,0,0,.4);
	opacity: 0; transition: opacity .3s ease;
}
.kush-cart-backdrop.is-visible { opacity: 1; }

.meadow-cart-sidebar {
	position: fixed !important; top: 0 !important; right: 0 !important; bottom: 0; left: auto !important;
	width: min(420px, 92vw) !important; max-width: 92vw; height: 100% !important; z-index: 9999 !important;
	background: var(--c-white) !important; box-shadow: -20px 0 60px rgba(0,0,0,.18);
	transform: translateX(100%); transition: transform .35s cubic-bezier(.4,0,.2,1);
	display: flex !important; flex-direction: column; overflow: hidden;
	border: 0 !important;
}
.meadow-cart-sidebar.open { transform: translateX(0) !important; }
/* Closed: push fully off-screen past the scrollbar gutter and drop shadow/border, so no sliver
   or WP-blue default border line pokes in at the viewport's right edge on desktop pages. */
.meadow-cart-sidebar:not(.open) { transform: translateX(calc(100% + 30px)) !important; box-shadow: none !important; }
.meadow-cart-header {
	display: flex; align-items: center; justify-content: space-between; gap: 12px;
	padding: 24px; border-bottom: 1px solid var(--c-divider); flex: 0 0 auto;
}
.meadow-cart-header strong { font-size: var(--fs-20); font-weight: var(--fw-medium); }
.meadow-cart-header button {
	width: 40px; height: 40px; border-radius: var(--r-pill); border: 1px solid var(--c-border);
	background: var(--c-white); font-size: 20px; line-height: 1; cursor: pointer; color: var(--c-text);
}
.meadow-cart-header button:hover { background: var(--c-green-light-50); }
.meadow-cart-content { flex: 1 1 auto; overflow-y: auto; padding: 20px 24px; }
.meadow-cart-content > p { color: var(--c-text-muted); text-align: center; padding: 40px 0; }
/* Cart line items: force each row into a flex row so name / qty / price / × always sit centred on
   ONE line regardless of name length (the native table layout let long names push cells off-row and
   aligned cells on the text baseline instead of centre). Name flexes + ellipsis; the rest stay put. */
.meadow-cart-table { width: 100%; display: block; }
.meadow-cart-table thead, .meadow-cart-table th { display: none; }
.meadow-cart-table tbody { display: block; width: 100%; }
.meadow-cart-table tr { display: flex; align-items: center; gap: 12px; border-bottom: 1px solid var(--c-divider); }
/* Drop the leftover "Product/Quantity/Price" header row (item rows carry data-product-id; it doesn't) —
   a slide-out cart drawer doesn't need column headers. */
.meadow-cart-table tr:not([data-product-id]) { display: none; }
.meadow-cart-table td { padding: 14px 0; font-size: var(--fs-14); border: 0; }
.meadow-cart-table td:first-child { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: var(--fw-medium); }
.meadow-cart-table td:not(:first-child) { flex: 0 0 auto; }
.meadow-cart-table td:nth-child(3) { min-width: 56px; text-align: right; }
.meadow-cart-qty {
	width: 56px; height: 40px; padding: 0 8px; border-radius: var(--r-card-sm); border: 1px solid var(--c-border);
	font-family: inherit; text-align: center;
}
.meadow-remove-product {
	width: 32px; height: 32px; border-radius: var(--r-pill); border: 1px solid var(--c-border); background: var(--c-white);
	cursor: pointer; position: relative; color: transparent;
}
.meadow-remove-product::before { content: "×"; position: absolute; inset: 0; display: grid; place-items: center; color: var(--c-text); font-size: 16px; }
.meadow-remove-product:hover { background: #fbeaea; border-color: #e3b7b7; }
.meadow-cart-footer { flex: 0 0 auto; padding: 20px 24px; border-top: 1px solid var(--c-divider); background: var(--c-white); }
.meadow-cart-summary { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
.meadow-cart-summary > div, .meadow-cart-total { display: flex; justify-content: space-between; font-size: var(--fs-14); }
.meadow-cart-total { font-weight: var(--fw-medium); font-size: var(--fs-body); padding-top: 8px; border-top: 1px solid var(--c-divider); }
.meadow-cart-actions { display: flex; gap: 10px; }
.meadow-checkout-btn {
	flex: 1; text-align: center; padding: 16px; border-radius: var(--r-pill); background: var(--c-black); color: #fff;
	font-weight: var(--fw-medium); transition: opacity .15s ease;
}
.meadow-checkout-btn:hover { opacity: .9; }
#meadow-reset-cart {
	padding: 16px 20px; border-radius: var(--r-pill); border: 1px solid var(--c-border); background: var(--c-white);
	font-family: inherit; font-weight: var(--fw-medium); cursor: pointer;
}
#meadow-reset-cart:disabled { opacity: .4; cursor: not-allowed; }
body.cart-open { overflow: hidden; }

/* Checkout */
.checkout { padding-top: 140px; }
.checkout__head { margin-bottom: 32px; }
/* The Meadow shortcode prints its own <h2>Checkout</h2> inside the form column,
   directly under this template's <h1>Checkout</h1> — the word appeared twice.
   The page heading is the correct one, so hide the plugin's (kept in the
   accessibility tree via the h1; this only removes the visual duplicate). */
.checkout__body .meadow-checkout-form-column > h2 { display: none; }
.meadow-checkout-container { display: grid; grid-template-columns: 1.3fr 1fr; gap: var(--gap-section); align-items: start; }
.meadow-checkout-form { display: flex; flex-direction: column; gap: 18px; }
.meadow-form-group { display: flex; flex-direction: column; gap: 6px; }
.meadow-form-group label { font-size: var(--fs-14); font-weight: var(--fw-medium); }
.meadow-checkout-form input, .meadow-checkout-form select {
	height: 52px; padding: 0 18px; border-radius: var(--r-card); border: 1px solid var(--c-border);
	font-family: inherit; font-size: var(--fs-body); background: var(--c-white); color: var(--c-text);
}
/* Select: swap the native OS chevron for the brand chevron with proper padding so
   the value never runs under it (matches .shop-select). */
.meadow-checkout-form select {
	appearance: none; -webkit-appearance: none; -moz-appearance: none;
	padding-right: 44px; cursor: pointer;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='black' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat; background-position: right 18px center;
}
/* Date / datetime / time fields keep the native CALENDAR icon, aligned to the same right:18px
   as the select chevrons so the whole checkout column of controls lines up. The checkout JS in
   main.js also opens the native picker on any click of the field. */
.meadow-checkout-form input[type="date"],
.meadow-checkout-form input[type="datetime-local"],
.meadow-checkout-form input[type="time"] {
	padding-right: 18px; cursor: pointer;
	/* iOS Safari sizes these from their VALUE rather than their box: with the
	   default appearance they keep an intrinsic content width, ignore the flex
	   stretch, and rendered wider than the card — "5 Mar 2006" and the pickup
	   datetime ran past the right edge on a phone while every other field
	   behaved. Desktop Chrome does not reproduce it (it reports appearance:auto
	   but still stretches), so this is written for the platform that breaks.
	   appearance:none + an explicit width is the pair that actually holds; width
	   alone is not enough on iOS. */
	-webkit-appearance: none; appearance: none;
	width: 100%; min-width: 0; max-width: 100%;
	text-align: left;
}
.meadow-checkout-form input[type="date"]::-webkit-calendar-picker-indicator,
.meadow-checkout-form input[type="datetime-local"]::-webkit-calendar-picker-indicator,
.meadow-checkout-form input[type="time"]::-webkit-calendar-picker-indicator {
	opacity: .6; cursor: pointer; margin-right: 0; margin-left: 0; transition: opacity .15s ease;
}
.meadow-checkout-form input[type="date"]:hover::-webkit-calendar-picker-indicator,
.meadow-checkout-form input[type="datetime-local"]:hover::-webkit-calendar-picker-indicator,
.meadow-checkout-form input[type="time"]:hover::-webkit-calendar-picker-indicator { opacity: 1; }
.meadow-checkout-form input:focus, .meadow-checkout-form select:focus { outline: 2px solid var(--c-green-mid); outline-offset: 1px; }
/* Age-gate / validation error surfaced by the checkout JS (main.js). */
.meadow-checkout-message--error { display: block; color: #b3261e; background: #fdecea; border: 1px solid #f5c2bd; border-radius: 12px; padding: 12px 16px; margin-top: 10px; font-size: var(--fs-14); }
.meadow-checkout-summary-column { background: var(--c-green-light-50); border-radius: var(--r-panel); padding: 28px; position: sticky; top: 100px; }
/* The plugin makes .meadow-order-summary its own white card (30px padding, 8px
   radius, a grey drop shadow) INSIDE our green panel — a card in a card. That
   second frame cost 60px of horizontal room, and on a 390px phone left the
   figures just 222px of the screen. Flatten it: the green panel is the card, and
   this is only the layout inside it. */
.meadow-order-summary {
	display: flex; flex-direction: column; gap: 10px;
	background: none; box-shadow: none; border-radius: 0; padding: 0;
}
.meadow-order-summary h3 { font-size: var(--fs-card-title); margin: 0 0 6px; }
.meadow-summary-row { display: flex; justify-content: space-between; gap: 12px; font-size: var(--fs-14); }
.meadow-summary-total { font-weight: var(--fw-medium); font-size: var(--fs-body); padding-top: 10px; border-top: 1px solid var(--c-border); }
/* The plugin emits a placeholder row for discounts that stays empty on most
   orders; it read as a mystery gap between Tax and Total. */
.meadow-summary-row:empty { display: none; }

/* Tax info tooltip.
   The plugin renders an ℹ️ emoji with a native title attribute: it paints as a
   blue OS glyph that fights the palette, and a native tooltip is slow to appear,
   unstyleable, and never shows on touch. main.js moves the title onto data-tip
   and adds .kush-tip, so this owns the whole thing. Neutral grey, not brand
   green, because it is an explanation and not a call to action. */
.kush-tip {
	position: relative; display: inline-grid; place-items: center;
	width: 16px; height: 16px; margin-left: 6px; padding: 0;
	border-radius: 50%; background: var(--c-text-muted); color: var(--c-white);
	font-size: 11px; font-weight: var(--fw-medium); font-style: normal;
	line-height: 1; cursor: help; vertical-align: middle;
	border: 0; -webkit-appearance: none; appearance: none;
}
.kush-tip::after {
	content: attr(data-tip);
	position: absolute; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%) translateY(4px);
	width: max-content; max-width: 240px; padding: 9px 12px;
	background: #3a3a3a; color: #fff; border-radius: 10px;
	font-size: var(--fs-12); font-weight: 400; line-height: 1.45; text-align: left;
	white-space: normal; opacity: 0; pointer-events: none;
	transition: opacity .14s ease, transform .14s ease;
	z-index: 20;
}
/* The little arrow. Separate pseudo so it can sit under the bubble's radius. */
.kush-tip::before {
	content: ""; position: absolute; bottom: calc(100% + 3px); left: 50%;
	transform: translateX(-50%) translateY(4px);
	border: 5px solid transparent; border-top-color: #3a3a3a;
	opacity: 0; pointer-events: none;
	transition: opacity .14s ease, transform .14s ease;
	z-index: 20;
}
.kush-tip:hover::after, .kush-tip:focus-visible::after,
.kush-tip:hover::before, .kush-tip:focus-visible::before {
	opacity: 1; transform: translateX(-50%) translateY(0);
}
/* Near the right edge of the summary the bubble would overflow the card. */
.meadow-summary-row .kush-tip::after { left: 0; transform: translateX(-4px) translateY(4px); }
.meadow-summary-row .kush-tip:hover::after,
.meadow-summary-row .kush-tip:focus-visible::after { transform: translateX(-4px) translateY(0); }
.meadow-summary-row .kush-tip::before { left: 12px; }
@media (prefers-reduced-motion: reduce) {
	.kush-tip::after, .kush-tip::before { transition: none; }
}
.meadow-confirm-order-btn {
	width: 100%; margin-top: 20px; padding: 18px; border-radius: var(--r-pill); border: none; background: var(--c-black);
	color: #fff; font-family: inherit; font-weight: var(--fw-medium); font-size: var(--fs-body); cursor: pointer;
}
.meadow-confirm-order-btn:disabled { opacity: .4; cursor: not-allowed; }
.meadow-terms-text, .meadow-warning { font-size: var(--fs-12); color: var(--c-text-muted); margin-top: 12px; }
.meadow-checkout-products { margin-top: 24px; }
.meadow-checkout-products .meadow-product-item { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-top: 1px solid var(--c-border); }
.meadow-product-thumbnail-placeholder { width: 48px; height: 48px; border-radius: var(--r-card-sm); background: var(--c-green-light); }
.meadow-checkout-products img { width: 48px; height: 48px; object-fit: contain; border-radius: var(--r-card-sm); background: var(--c-green-light); }
/* Order confirmation.
   The plugin ships this screen in its own visual language — a #28a745 heading and
   icon, a #0073aa link-button, an 8px radius and a grey drop shadow, plus a
   `margin: 20px` on phones that pinched it narrower than every other card on the
   site. Everything below re-skins that markup (built in meadow-cart.js, so it
   can't be edited at source) to the theme: black type, brand green icon, our
   panel radius and a real .btn--primary pill. */
.meadow-order-success {
	text-align: center;
	max-width: 640px;
	margin: 0 auto;
	padding: 56px 40px;
	background: var(--c-white);
	border: 1px solid var(--c-border);
	border-radius: var(--r-panel);
	box-shadow: none;
}
.meadow-success-icon {
	width: 72px; height: 72px; border-radius: 50%;
	background: var(--c-green-light);
	/* Black tick, not the plugin's white — it vanished against the light green. */
	color: var(--c-black);
	display: grid; place-items: center; margin: 0 auto 24px;
	font-size: 34px; line-height: 1;
}
.meadow-order-success h2 {
	color: var(--c-black);
	font-size: var(--fs-card-title);
	line-height: 1.2;
	margin: 0 0 24px;
	text-wrap: balance;
}
.meadow-order-details {
	display: block;            /* plugin sets inline-block, which shrink-wrapped it */
	background: var(--c-green-light-50);
	border-radius: var(--r-card);
	padding: 20px 24px;
	margin: 0 0 24px;
	text-align: left;
}
.meadow-order-details p { margin: 6px 0; font-size: var(--fs-14); }
.meadow-success-message { color: var(--c-text-muted); font-size: var(--fs-body); margin: 0 0 28px; }
.meadow-checkout-empty { text-align: center; padding: 60px 20px; color: var(--c-text-muted); }
.meadow-checkout-empty a { text-decoration: underline; font-weight: var(--fw-medium); }
/* Match .btn/.btn--primary exactly rather than approximating it. */
.meadow-continue-shopping {
	display: inline-flex; align-items: center; justify-content: center; gap: var(--gap-xs);
	min-height: var(--btn-h);
	padding: 16px 32px;
	border-radius: var(--r-pill);
	border: 1px solid var(--c-black);
	background: var(--c-black);
	color: var(--c-white);
	font-weight: var(--fw-medium); font-size: var(--fs-body); line-height: 1;
	text-decoration: none;
	transition: transform .15s ease, opacity .15s ease;
}
.meadow-continue-shopping:hover, .meadow-continue-shopping:focus-visible {
	background: var(--c-black); color: var(--c-white); text-decoration: none; opacity: .9;
}
@media (max-width: 560px) {
	/* Undo the plugin's `margin: 20px`, which inset this card inside the page
	   gutter that .checkout.container already provides. */
	.meadow-order-success { margin: 0 auto; padding: 40px 22px; }
	.meadow-order-details { padding: 18px; }
}

@media (max-width: 860px) {
	.meadow-checkout-container { grid-template-columns: 1fr; gap: 32px; }
	.meadow-checkout-summary-column { position: static; }
	/* Grid items default to min-width:auto and were refusing to shrink below their content, so each
	   column rendered ~405px inside a ~318px track → ~50px of horizontal page overflow on phones
	   (form fields + the date calendar icons ran off the right edge). Let them shrink to the track. */
	.meadow-checkout-form-column, .meadow-checkout-summary-column { min-width: 0; }
}
@media (max-width: 640px) {
	/* The plugin insets .meadow-checkout-wrapper by 20px, but .checkout.container
	   already supplies the page gutter — it was a second margin inside the first.
	   Removing it hands ~40px back to the columns on a phone. */
	.meadow-checkout-wrapper { padding-left: 0; padding-right: 0; }
}
@media (max-width: 480px) {
	.meadow-checkout-form-column, .meadow-checkout-summary-column { padding-left: 18px; padding-right: 18px; }
}
/* Order-summary line items on phones. The plugin lays each row out as a flex
   line — 80px thumb + .meadow-product-info{flex:1;min-width:0} + a nowrap
   .meadow-product-total. At 390px the row box is only ~222px wide, so after the
   thumb, the gaps and the ~90px total, the info column collapsed to ~22px: the
   product name wrapped to five lines and the price printed on top of it.
   Re-lay the row as a grid and drop the total onto its own line under the name.
   !important + a selector at least as specific as the plugin's, because its
   rules are themselves !important. */
@media (max-width: 560px) {
	.meadow-checkout-wrapper .meadow-checkout-products .meadow-product-item {
		display: grid !important;
		grid-template-columns: 80px minmax(0, 1fr);
		align-items: start !important;
		column-gap: 12px; row-gap: 4px;
	}
	.meadow-checkout-wrapper .meadow-checkout-products .meadow-product-item .meadow-product-info {
		grid-column: 2; min-width: 0 !important;
	}
	.meadow-checkout-wrapper .meadow-checkout-products .meadow-product-item .meadow-product-total {
		grid-column: 2; text-align: left !important; margin-left: 0 !important; white-space: normal !important;
	}
	.meadow-checkout-wrapper .meadow-checkout-products .meadow-product-item .meadow-product-name {
		overflow-wrap: anywhere;
	}
}

/* ==========================================================================
   Pre-page — 21+ age gate + landing sequence (Figma 20208:85 / 35 / 192 / 109)
   Theme-owned overlay; markup in template-parts/prepage.php, logic in main.js.
   ========================================================================== */
html.pp-active { overflow: hidden; }              /* lock scroll while the gate/intro is up */

/* Defensive: if the old Age Gate plugin is still active, hide its gate — the
   theme now owns verification. (Deactivate the plugin to be safe.) */
.age-gate__wrapper, body > .age-gate { display: none !important; }
/* ...and neutralise the lock that gate leaves behind. The Age Gate plugin's JS
   puts .age-gate__restricted on <html>, whose rule is
   `height: 100vh; overflow: var(--ag-html-overflow, hidden)` — a hard scroll
   lock it only lifts when ITS form is submitted. We hide that form (the theme's
   own 21+ pre-page replaced it), so the lock could never be released and every
   page became unscrollable while looking perfectly normal. Age verification is
   unaffected: template-parts/prepage.php still gates entry.
   NB: overflow-y must be set on its own — a blanket `overflow: visible` would
   also drop the overflow-x: clip guard on <html>. */
html.age-gate__restricted,
html.age-gate__restricted--js {
	height: auto !important;
	overflow-x: clip !important;
	overflow-y: visible !important;
	--ag-html-overflow: visible;
}
/* The JointCommerce/Meadow pixel script appends a bare "Powered by
   JointCommerce" link to <body> (no class/id) — hide it (Shawn). */
body > a[href*="jointcommerce.com"] { display: none !important; }

#kush-prepage {
	position: fixed; inset: 0; z-index: 100000; overflow: hidden;
	opacity: 1; transition: opacity .9s ease; will-change: opacity;
}
/* Already age-verified this browser session (html.pp-verified is set by the
   header.php pre-paint script): no gate, no intro, on any page — main.js
   removes the node on DOMContentLoaded. */
html.pp-verified #kush-prepage { display: none; }
/* Fog lifts → homepage shows through. pointer-events none: the page beneath
   is interactive from the first frame of the fade, not after removal. The
   exit fade is short — the hero scene under it is identical, so it only has
   to mask sub-pixel differences while the page chrome animates in. */
#kush-prepage.pp--reveal, #kush-prepage.pp--exit { opacity: 0; pointer-events: none; }
#kush-prepage.pp--exit { transition-duration: .45s; }

/* Gated first paint: the header and hero UI are held hidden while the
   pre-page owns the screen. During the frame-2/3 flight (html.pp-rise, added
   at "Yes") the title/buttons and carousel ride up from below the viewport
   IN SYNC WITH THE FOG — same 2.4s curve, displaced by the fog's own travel
   (--pp-rise, set by main.js) so they visibly follow the clouds up (Shawn).
   The page's own wordmark/clouds stay hidden until hand-off (the overlay
   flies its copies; two at once is the cardinal sin), then crossfade in as
   the overlay fades out. The header drops in from the top at hand-off. */
.site-header { transition: opacity .6s ease, transform .6s ease; }
/* Doubled classes: must outrank .js-anim .reveal.is-visible on the carousel. */
html.pp-active .site-header.site-header { opacity: 0; transform: translateY(-16px); transition: none; }
html.pp-active .hero__inner.hero__inner, html.pp-active .hero__carousel.hero__carousel {
	opacity: 0; transform: translateY(var(--pp-rise, 100vh)); transition: none;
}
.hero__scene-wordmark, .hero__scene-clouds { transition: opacity .45s ease; }
html.pp-active .hero__scene-wordmark, html.pp-active .hero__scene-clouds { opacity: 0; transition: none; }
/* Flight: later in the file than the pp-active rules, same specificity → wins
   while both classes are on <html>. */
html.pp-rise .hero__inner.hero__inner, html.pp-rise .hero__carousel.hero__carousel {
	opacity: 1; transform: none;
	transition: transform 2.4s cubic-bezier(.25,.1,.25,1), opacity .8s ease;
	/* Above the overlay (z 100000): at rest the title paints over the clouds
	   (content z2 vs scene z0), so during the flight it must ride IN FRONT of
	   the fog band too — its opaque lower half was swallowing the text. Both
	   elements sit in the root stacking context (no ancestor creates one), so
	   this wins over the overlay. Input still off until hand-off. */
	z-index: 100001; pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
	.site-header, .hero__inner, .hero__carousel, .hero__scene-wordmark, .hero__scene-clouds { transition: none !important; }
}

/* Green→white gradient (frame 1). Fades OUT during the flight, revealing the
   REAL hero scene underneath — the overlay no longer carries a scene of its
   own, it only flies the wordmark and fog above the live page. */
.pp__bg {
	position: absolute; inset: 0;
	background: linear-gradient(180deg, rgb(200,230,140) 0%, rgb(216,244,160) 20.2%, #ffffff 64.8%);
	transition: opacity 1.2s ease;
}

/* KUSHOLOGY wordmark — ONE element across all three frames; it only moves.
   The PNG's alpha is used as a mask so the fill can crossfade from the frame-1
   photo fill to the frame-2/3 cream (Figma soft-light) without a second copy. */
.pp__wordmark {
	position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; pointer-events: none;
	height: clamp(110px, 23vw, 333px); color: transparent; opacity: .98;
	-webkit-mask: url(../img/prepage-wordmark.png) center bottom / contain no-repeat;
	mask: url(../img/prepage-wordmark.png) center bottom / contain no-repeat;
	will-change: transform;
	transition: transform 2.4s cubic-bezier(.25,.1,.25,1), opacity 1s ease;
}
.pp__wordmark::before,
.pp__wordmark::after {
	content: ""; position: absolute; inset: 0;
	transition: opacity 1.4s ease .4s;  /* fill crossfades mid-flight */
}
.pp__wordmark::before { background: url(../img/prepage-wordmark.png) center bottom / contain no-repeat; }  /* photo fill (frame 1) */
.pp__wordmark::after { background: #fff; opacity: 0; }  /* fill (frames 2-3) — must match .hero__scene-wordmark, this is what lands on it */
#kush-prepage.pp--f2 .pp__wordmark::before,
#kush-prepage.pp--f3 .pp__wordmark::before { opacity: 0; }
#kush-prepage.pp--f2 .pp__wordmark::after,
#kush-prepage.pp--f3 .pp__wordmark::after { opacity: 1; }  /* == .hero__scene-wordmark's opacity: the flight lands on it, so any gap shows as a fade at hand-off */

/* Fog cloud band (Figma footer-clouds 20208:43, transparent top → white bottom).
   Node geometry: x -240, w 1920, h 766 on the 1440 frame → -16.7vw / 133.4vw / 53.2vw.
   Frame 1: below the viewport. Frame 2: top 304px (29.7vh). Frame 3: top 55px (5.4vh).
   Moved with transform only — compositable, no layout thrash. */
.pp__fog {
	position: absolute; left: -16.7vw; top: 0; width: 133.4vw; height: 53.2vw; z-index: 3; pointer-events: none;
	background: url(../img/prepage-fog.png) center top / 100% 100% no-repeat;
	transform: translateY(100vh); transform-origin: top left; will-change: transform;
	transition: transform 2.4s cubic-bezier(.25,.1,.25,1);
}
/* No under-sheet: the area below the fog band shows the live page, so the
   content is what rises there — not a white screen. */

/* --- Age-gate card (frame 1) ------------------------------------------- */
.pp__gate {
	position: absolute; inset: 0; z-index: 5;
	/* Figma 20208:85: the gate column is pinned 200px from the top (19.5vh),
	   not vertically centred — this keeps the Figma air between the license
	   line and the bottom wordmark. */
	display: flex; align-items: flex-start; justify-content: center;
	padding: 19.5vh 24px 24px;
	transition: opacity .45s ease, transform .45s ease;
}
.pp__card { width: 100%; max-width: 460px; display: flex; flex-direction: column; align-items: center; gap: var(--gap-lg); text-align: center; }
.pp__card[hidden] { display: none; }  /* beat the .pp__card display:flex above */
.pp__text { display: flex; flex-direction: column; align-items: center; gap: var(--gap-xs); }
.pp__eyebrow { margin: 0; color: #3f6000; font-weight: var(--fw-medium); font-size: var(--fs-12); letter-spacing: .12em; text-transform: uppercase; }
.pp__title { margin: 0; color: var(--c-black); font-weight: var(--fw-medium); font-size: clamp(28px, 5vw, 40px); line-height: 1.15; }
.pp__sub { margin: 0; max-width: 369px; color: var(--c-text-muted); font-size: var(--fs-14); line-height: var(--lh-body); }
.pp__sub a { color: var(--c-black); text-decoration: underline; font-weight: var(--fw-medium); }
.pp__buttons { display: flex; gap: var(--gap-sm); justify-content: center; flex-wrap: wrap; }
.pp__btn {
	min-width: 200px; max-width: 100%; padding: 16px 32px; border-radius: var(--r-pill);
	font-family: var(--font-sans); font-weight: var(--fw-medium); font-size: var(--fs-body);
	line-height: 1; white-space: nowrap; cursor: pointer; border: 1px solid transparent;
	transition: opacity .2s ease, transform .2s ease;
}
.pp__btn:hover { opacity: .9; transform: translateY(-1px); }
.pp__btn--yes { background: var(--c-black); color: var(--c-white); }
.pp__btn--no  { background: var(--c-white); color: var(--c-black); border-color: var(--c-border); }
.pp__remember {
	display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
	font-size: var(--fs-14); font-weight: var(--fw-medium); color: var(--c-text);
}
.pp__remember input {
	appearance: none; -webkit-appearance: none; width: 18px; height: 18px; margin: 0;
	border: 1.5px solid var(--c-border); border-radius: 5px; background: var(--c-white);
	display: grid; place-items: center; cursor: pointer;
	transition: background .15s ease, border-color .15s ease;
}
.pp__remember input::after {
	content: ""; width: 10px; height: 10px; opacity: 0; transition: opacity .12s ease;
	background: var(--c-black);
	-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.5L4.7 9 10 3.5' stroke='black' stroke-width='2.2' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
	mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.5L4.7 9 10 3.5' stroke='black' stroke-width='2.2' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}
.pp__remember input:checked { background: var(--c-green-mid); border-color: var(--c-green-mid); }
.pp__remember input:checked::after { opacity: 1; }
.pp__license { margin: 0; white-space: nowrap; color: rgba(0,0,0,.7); font-size: var(--fs-10); line-height: var(--lh-body); }  /* single line per Figma */
.pp__card--denied { gap: var(--gap-md); }

/* --- Frame states (Figma 20208:85 / :35 / :192) -------------------------
   Frame 1 = default: gate card, green gradient, wordmark at the bottom.
   Frame 2 (.pp--f2): bridge scene, wordmark centred (~50vh, 85.4vw), fog low.
   Frame 3 (.pp--f3): same scene, wordmark up (~25vh), fog high.
   "Yes" steps f1 → f2 → f3 → reveal; each state is also viewable statically
   via ?ppframe=1|2|3 for design review. */
#kush-prepage.pp--f2 .pp__gate,
#kush-prepage.pp--f3 .pp__gate { opacity: 0; transform: translateY(-24px); pointer-events: none; }
/* The frame-1 gradient clears out of the way — the live hero is the scene. */
#kush-prepage.pp--f2 .pp__bg,
#kush-prepage.pp--f3 .pp__bg { opacity: 0; }
/* Wordmark: base centre ≈ 83.8vh / ≈99vw wide → f2 centre 50vh, f3 centre 25.4vh.
   The f3 landing is measured from the LIVE hero wordmark by main.js (custom
   properties) so the flight ends exactly on the hero's glyphs at any viewport;
   the static values are the fallback for the ?ppframe review URLs. */
#kush-prepage.pp--f2 .pp__wordmark { transform: translateY(-33.8vh) scale(.854); }
#kush-prepage.pp--f3 .pp__wordmark {
	transform: translate(var(--pp-wm-tx, 0px), var(--pp-wm-ty, -58.4vh)) scale(var(--pp-wm-s, .854));
}
#kush-prepage.pp--f2 .pp__fog { transform: translateY(29.7vh); }
/* Fog f3 landing likewise measured onto the hero's clouds layer. */
#kush-prepage.pp--f3 .pp__fog { transform: var(--pp-fog-t, translateY(5.4vh)); }

/* Both plates bake the scene's fog in, and it is always there under the overlay —
   so the rising band dissolves INTO it on the way up instead of being swapped out
   at the end. It reaches zero right as the flight lands, leaving one fog (the
   plate's) and nothing for the hand-off to change. The ease-in holds it solid
   through the early travel, where it is doing the actual work. */
.pp__fog { transition: transform 2.4s cubic-bezier(.25,.1,.25,1), opacity 1.4s ease-in 1s; }
#kush-prepage.pp--f3 .pp__fog { opacity: 0; }

/* The hero's clouds drift ±60px forever; hold them at their start pose while
   the gate is up so the overlay fog has a stationary target to land on (the
   drift resumes, gently, when pp-active is dropped at hand-off). */
html.pp-active .hero__scene-clouds { animation-play-state: paused; }

@media (prefers-reduced-motion: reduce) {
	#kush-prepage, .pp__bg, .pp__wordmark, .pp__fog, .pp__gate { transition: none !important; }
}
@media (max-width: 900px) {
	.pp__btn { width: 100%; }
	.pp__license { white-space: normal; }  /* one line doesn't fit small screens */
	.pp__fog { left: -50vw; width: 200vw; }
	#kush-prepage.pp--transition .pp__wordmark { transform: translateY(-55vh) scale(.9); }
}

/* --- Responsive --------------------------------------------------------- */
/* The burger used to take over only at 900px, so between 901 and ~1199px the
   four primary links, the centred logo and the nowrap "1019 Ocean Ave | 6AM -
   10PM" pill all competed for one row: every nav <a> wrapped to two lines (48px
   tall) and crowded the logo. Verified broken at 1024 and 1100, clean at 1200.
   Hiding the pill and tightening the gap is not enough to close it: the header
   is a 1fr/auto/1fr grid, so at 901px the nav column is only ~349px while the
   four links need ~422px unwrapped. Shrinking type that far would be worse than
   the burger, so the burger now takes over at 1200 — the width where the row
   genuinely fits. Only the nav/burger rules move up; the rest of the mobile
   layout still starts at 900px. */
@media (max-width: 1200px) {
	.site-header__nav, .site-header__location { display: none; }
	/* The header is a 1fr/auto/1fr grid and the nav is its first item. Hiding the
	   nav takes it out of flow, so auto-placement pulled the logo into column 1
	   and the actions into column 2 — the logo landed at x=228 instead of centred.
	   Pin both back to their own columns. */
	.site-header__logo { grid-column: 2; }
	.site-header__actions { grid-column: 3; }
	.site-header__toggle {
		display: grid; place-items: center; width: 44px; height: 44px;
		background: none; border: none; cursor: pointer;
	}
	.site-header__toggle-bar, .site-header__toggle-bar::before, .site-header__toggle-bar::after {
		content: ""; display: block; width: 22px; height: 2px; background: var(--c-black); position: relative;
	}
	.site-header__toggle-bar::before { position: absolute; top: -7px; }
	.site-header__toggle-bar::after { position: absolute; top: 7px; }
	/* Mobile dropdown nav — full-width panel below the header bar, so it reads as
	   dropping from the whole bar (incl. the right-side hamburger that opens it)
	   rather than a stray box in the corner.
	   justify-self:stretch is REQUIRED: the nav is a grid item with justify-self:start
	   (desktop), and on an absolutely-positioned grid item that shrink-wraps it and
	   pins it left — so left:0/right:0 was ignored and the panel sat 159px on the
	   left, disconnected from the hamburger. Stretch lets left:0/right:0 fill. */
	/* Scroll lock while the menu panel is up (set by main.js alongside .nav-open).
	   overflow-y only — a blanket `overflow: hidden` would drop the overflow-x
	   guard <html> relies on, same reason as the age-gate reset above. */
	html.nav-locked { overflow-y: hidden; }
	body.nav-open .site-header__nav {
		display: block; position: absolute; top: calc(100% + 8px);
		/* Inset 16px from the viewport so the card matches the width of the on-scroll
		   dropdown, which rides the inset frosted pill. At the top the bar is
		   full-width, so without this the card would go edge-to-edge (wider). */
		left: 16px; right: 16px;
		justify-self: stretch; width: auto;
		/* Frosted glass matching the header pill, as a standalone rounded card that
		   drops below the bar. */
		background-color: rgba(255, 255, 255, 0.92);
		-webkit-backdrop-filter: blur(16px) saturate(1.6);
		backdrop-filter: blur(16px) saturate(1.6);
		border: 1px solid rgba(255, 255, 255, 0.55);
		border-radius: var(--r-panel);
		box-shadow: 0 12px 28px rgba(0, 0, 0, 0.12);
		padding: 8px var(--container-pad) 12px;
	}
	/* When stuck, the bar is ALREADY an inset pill, so the card anchors flush to it
	   (left:0/right:0 == the pill's inset). Keeps the width identical to the top state. */
	body.nav-open .site-header.is-stuck .site-header__nav { left: 0; right: 0; }
	body.nav-open .site-header__nav .primary-menu { flex-direction: column; gap: 2px; }
	body.nav-open .site-header__nav .primary-menu a {
		display: block; padding: 13px 12px; border-radius: 12px;
		font-size: 16px; transition: background .15s ease, color .15s ease;
	}
	body.nav-open .site-header__nav .primary-menu a:hover,
	body.nav-open .site-header__nav .primary-menu a:focus-visible { background: var(--c-green-light); }
}
@media (max-width: 1100px) {
	.featured__grid { grid-template-columns: repeat(3, 1fr); }
	.faq { grid-template-columns: 1fr; }
	.faq__list { width: auto; }
}
@media (max-width: 900px) {
	.panel__row { grid-template-columns: 1fr; }
	.featured__grid { gap: 32px var(--gap-md); margin: 48px 0; }
	.band { min-height: 560px; }
	.hero { padding-top: 140px; }
	/* Portrait: the canvas' height-driven cover scale crops the sides but keeps
	   the tower centred; no per-layer overrides needed. */
	.tile--category, .tile--location { flex-basis: 82vw; width: 82vw; }
}
/* NB: the ≤560px .featured__grid / .signup__row rules that used to live here were
   dead — later ≤900px blocks re-declare both, and at equal specificity the later
   declaration wins for every viewport they both match. Removed so the file stops
   implying a 2-column mobile grid that never rendered; the Figma mobile spec is
   the 3×3-of-9 set in the ≤900px block. */

/* ==========================================================================
   Shop — our product cards / grid / filters
   ========================================================================== */
.shop { padding-top: 140px; }
.shop__head { margin-bottom: 24px; }
.shop__lede { margin-top: 8px; max-width: 640px; }

.shop-filters { display: flex; flex-direction: column; gap: 16px; margin-bottom: 32px; }
.shop-filters__selects { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; }
.shop-filters__field { display: flex; flex-direction: column; gap: 6px; }
.shop-filters__field--sort { margin-left: auto; }
.shop-filters__label { font-size: var(--fs-12); color: var(--c-text-muted); font-weight: var(--fw-medium); letter-spacing: .04em; text-transform: uppercase; }
.shop-select {
	appearance: none; -webkit-appearance: none; min-width: 180px; height: 48px; padding: 0 40px 0 20px;
	border-radius: var(--r-pill); border: 1px solid var(--c-border); background: var(--c-white); cursor: pointer;
	font-family: inherit; font-size: var(--fs-14); color: var(--c-text);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='black' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat; background-position: right 18px center;
}
.shop-select:focus { outline: 2px solid var(--c-green-mid); outline-offset: 1px; }
.shop-filters__chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
	display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; border-radius: var(--r-pill);
	background: var(--c-green-light-50); font-size: var(--fs-14); font-weight: var(--fw-medium); transition: background .15s ease;
}
.chip:hover { background: var(--c-green-light); }
.chip--clear { background: transparent; text-decoration: underline; }

.product-grid__meta { margin-bottom: 16px; color: var(--c-text-muted); font-size: var(--fs-14); }
.product-grid { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: var(--gap-md); }

.product-card {
	position: relative; display: flex; flex-direction: column; border-radius: var(--r-card);
	background: var(--c-green-light); padding: 16px; overflow: hidden;
	transition: transform .18s ease, box-shadow .18s ease;
}
.product-card:hover { transform: translateY(-4px); box-shadow: 0 14px 30px rgba(0,0,0,.12); }
.product-card__add {
	position: absolute; top: 14px; right: 14px; z-index: 4; width: 34px; height: 34px; padding: 0;
	border-radius: var(--r-pill); border: 1px solid var(--c-border); background: var(--c-white);
	box-shadow: 0 2px 8px rgba(20, 46, 22, 0.16);
	display: grid; place-items: center; line-height: 1; color: var(--c-black);
	/* The Meadow plugin swaps this button's textContent to "Adding…/Added" on click
	   (setButtonLoading, meadow-cart.js) — which destroys the + span and, at the old
	   22px font, ballooned the word inside the 34px circle. Zero the button's own font
	   and clip overflow so that swapped text can't show or resize the button; the +
	   is drawn as a ::before pseudo, which survives the textContent overwrite. */
	font-size: 0; overflow: hidden;
	/* The + is a centred SVG background, not a text glyph — perfectly centred regardless of font
	   metrics, and immune to the plugin overwriting textContent. background-size/position own the
	   centring; hover must use background-color (not the `background` shorthand) to keep the icon. */
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14'%3E%3Cpath d='M7 1.5v11M1.5 7h11' stroke='%23111' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat; background-position: center; background-size: 14px 14px;
	transition: transform .15s ease, background-color .15s ease, opacity .15s ease;
}
.product-card__add::before { content: none; }
.product-card__add-plus { display: none; }
.product-card__add:hover { transform: scale(1.12); background-color: var(--c-green-mid); }
.product-card__add:disabled { opacity: .55; cursor: default; transform: none; }  /* brief loading state; the cart sidebar opening is the real feedback */
.product-card__add.is-added { background: var(--c-black); color: #fff; }
.product-card__media {
	position: relative; z-index: 1; display: grid; place-items: center; aspect-ratio: 1/1; margin-bottom: 12px;
}
.product-card__media::after {
	content: "KUSHOLOGY"; position: absolute; inset: 0; z-index: 0; display: grid; place-items: center;
	font-size: 13px; letter-spacing: .12em; font-weight: var(--fw-medium); color: rgba(0,0,0,.14); pointer-events: none;
}
.product-card__media img { position: relative; z-index: 1; max-width: 82%; max-height: 82%; object-fit: contain; }
.product-card__name { font-weight: var(--fw-medium); font-size: var(--fs-body); line-height: 1.25; }
.product-card__name:hover { text-decoration: underline; }
.product-card__meta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 6px; font-size: var(--fs-12); color: var(--c-text-muted); }
.product-card__meta .dot { width: 3px; height: 3px; border-radius: 50%; background: currentColor; }
.product-card__price .price ins { text-decoration: none; font-weight: var(--fw-medium); color: var(--c-text); }
.product-card__price .price del { opacity: .5; margin-right: 4px; }

.product-pagination { display: flex; gap: 8px; justify-content: center; margin-top: 48px; flex-wrap: wrap; }
.product-pagination .page-numbers {
	display: inline-grid; place-items: center; min-width: 44px; height: 44px; padding: 0 10px;
	border-radius: var(--r-pill); border: 1px solid var(--c-border); font-weight: var(--fw-medium); transition: background .15s ease;
}
.product-pagination .page-numbers:hover { background: var(--c-green-light-50); }
.product-pagination .page-numbers.current { background: var(--c-black); color: #fff; border-color: var(--c-black); }
.product-grid__empty { text-align: center; padding: 60px 20px; }

@media (max-width: 1100px) { .product-grid { grid-template-columns: repeat(3, minmax(0,1fr)); } }
@media (max-width: 760px) {
	.product-grid { grid-template-columns: repeat(2, minmax(0,1fr)); gap: 14px; }
	.shop-filters__selects { width: 100%; }
	.shop-filters__field { flex: 1 1 calc(50% - 6px); min-width: 0; }
	.shop-filters__field--sort { flex-basis: 100%; margin-left: 0; }
	.shop-select { min-width: 0; width: 100%; }
}
/* Keep the shop menu 2-up on phones — a single column turns 781 products into an
   endless one-card-per-screen scroll, and it read as broken next to the home
   page's own 3-up featured grid. 2 columns hold down to ~320px (cards ~140px). */
@media (max-width: 420px) {
	.product-grid { gap: 10px; }
}

/* ==========================================================================
   Legacy: Meadow plugin's [custom_product_filter] markup (kept for compatibility)
   ========================================================================== */
.shop { padding-top: 140px; }
.shop__head { margin-bottom: 40px; }
.shop__intro { margin-top: 12px; color: var(--c-text-muted); max-width: 720px; }

.meadow-wrapper { display: grid; grid-template-columns: 280px 1fr; gap: var(--gap-lg); align-items: start; }
.meadow-filters { position: sticky; top: 100px; display: flex; flex-direction: column; gap: 24px; }
.meadow-product-filter-form h3 { font-size: var(--fs-14); font-weight: var(--fw-medium); margin-bottom: 8px; }

.lb_prod_filter_attr_box { position: relative; margin-bottom: 20px; }
.lb_prod_filter_attr_title {
	display: flex; justify-content: space-between; align-items: center; gap: 8px; width: 100%;
	padding: 14px 20px; border-radius: var(--r-pill); border: 1px solid var(--c-border);
	background: var(--c-white); font-family: inherit; font-size: var(--fs-14); cursor: pointer;
}
.prod_filter_ul_wrapper { display: none; margin-top: 8px; }
.lb_prod_filter_attr_box.open .prod_filter_ul_wrapper { display: block; }
.prod_filter_ul { border: 1px solid var(--c-border); border-radius: var(--r-card); overflow: hidden; max-height: 280px; overflow-y: auto; }
.prod_filter_ul li { padding: 10px 16px; font-size: var(--fs-14); cursor: pointer; }
.prod_filter_ul li:hover, .prod_filter_ul li.selected { background: var(--c-green-light-50); }

.meadow-sort { display: flex; justify-content: flex-end; margin-bottom: 24px; }
.sort-select {
	padding: 12px 20px; border-radius: var(--r-pill); border: 1px solid var(--c-border);
	background: var(--c-white); font-family: inherit; font-size: var(--fs-14); cursor: pointer;
}

.meadow-product-list {
	display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--gap-md);
}
.meadow-product-item {
	display: flex; flex-direction: column; gap: 12px; border-radius: var(--r-card);
	background: var(--c-white); border: 1px solid var(--c-border); padding: 12px;
}
.meadow-product-thumbnail {
	position: relative; aspect-ratio: 1/1; border-radius: var(--r-card-sm); overflow: hidden;
	background: linear-gradient(to bottom, var(--c-green-light) 48%, var(--c-green-deep-50) 100%);
	display: grid; place-items: center;
}
.meadow-product-thumbnail img { width: 82%; height: 82%; object-fit: contain; }
.meadow-product-thumbnail .meadow-add-to-cart-btn {
	position: absolute; bottom: 8px; right: 8px; display: inline-flex; align-items: center; gap: 6px;
	padding: 8px 12px; border-radius: var(--r-pill); border: 1px solid var(--c-border);
	background: var(--c-white); font-family: inherit; font-size: var(--fs-12); font-weight: var(--fw-medium);
}
.meadow-product-thumbnail .meadow-add-to-cart-btn img { width: 16px; height: 16px; }
/* Single-page add-to-cart uses the standard .btn styling (see product-single__add). */
.product-single__add { display: inline-flex; align-items: center; gap: 8px; }
.product-single__add img { width: 18px; height: 18px; }
.meadow-product-content-body h3 { font-size: var(--fs-14); font-weight: var(--fw-medium); }
.meadow-product-content-body p { font-size: var(--fs-12); color: var(--c-text-muted); }
.meadow-product-view-btn {
	margin-top: auto; text-align: center; padding: 12px 16px; border-radius: var(--r-pill) !important;
	background: var(--c-black) !important; color: var(--c-white) !important;
	font-size: var(--fs-12); font-weight: var(--fw-medium); border: none;
}
.meadow-product-view-btn:hover { opacity: .9; }
.meadow-product-item { min-height: 100%; }
.meadow-product-content-body { flex: 0 0 auto; }
.meadow-pagination { display: flex; gap: 8px; justify-content: center; margin-top: 40px; }
.meadow-pagination .page-numbers {
	display: inline-grid; place-items: center; min-width: 40px; height: 40px; padding: 0 8px;
	border-radius: var(--r-pill); border: 1px solid var(--c-border);
}
.meadow-pagination .page-numbers.current { background: var(--c-black); color: var(--c-white); }

/* --- 404 + search ------------------------------------------------------- */
.error-404 { padding-top: 160px; text-align: center; }
.error-404__inner { max-width: 640px; margin: 0 auto; display: flex; flex-direction: column; align-items: center; }
.error-404__search, .search-results__form { max-width: 480px; margin: 28px auto 0; width: 100%; }
/* Scope to the section: `search-results` is ALSO a core WP body class (body.search-results on every
   results page), so a bare `.search-results{padding-top}` padded the <body> too — that pushed <main>
   down 140px AND the section added its own 140px = a 280px dead band above the H1. */
.search-results.container { padding-top: 140px; }
.search-results__head { margin-bottom: 40px; }
/* Generic archive/index template (index.php) — clear the fixed header. Without this the CPT-archive
   H1 (e.g. Neighborhoods) tucked under the header on mobile, where .section top padding is only 56px.
   Scoped .section.page-archive so it also wins inside the mobile .section breakpoint. */
.section.page-archive { padding-top: 140px; }
/* Non-product search hits (pages/posts) as a simple card that sits in the product grid. */
.product-card--result { justify-content: center; gap: 8px; min-height: 160px; text-align: center; padding: 24px; }
.product-card--result__kind { font-size: var(--fs-12); font-weight: var(--fw-medium); color: var(--c-text-muted); text-transform: uppercase; letter-spacing: .06em; }
.product-card--result__title { font-size: var(--fs-20); line-height: var(--lh-tight); }
.pcard__label { position: absolute; bottom: 10px; left: 12px; right: 12px; z-index: 2; font-size: var(--fs-14); font-weight: var(--fw-medium); color: var(--c-text); }
.pcard--page { background: var(--c-green-light-50); aspect-ratio: 16/9; }
.pcard--page::before { content: none; }
.search-form { display: flex; gap: 8px; align-items: center; }
/* WP's get_search_form() wraps the input in a <label> — THAT is the flex child,
   so the stretch/width lives on the label and the input fills it. */
.search-form label { flex: 1; display: block; min-width: 0; }
.search-form .search-field { width: 100%; height: 48px; padding: 0 20px; border-radius: var(--r-pill); border: 1px solid var(--c-border); font-family: inherit; }
.search-form .search-submit { height: 48px; padding: 0 24px; border-radius: var(--r-pill); border: none; background: var(--c-black); color: #fff; font-family: inherit; font-weight: var(--fw-medium); cursor: pointer; }

/* --- Generic page / long-form prose ------------------------------------- */
.page-single { padding-top: 140px; max-width: 860px; }
.page-single__head { margin-bottom: 32px; }
.page-single__content { color: var(--c-text-muted); }
.page-single__content h1, .page-single__content h2, .page-single__content h3 {
	color: var(--c-text); margin: 32px 0 12px;
}
.page-single__content h1 { font-size: var(--fs-card-title); }
.page-single__content h2 { font-size: var(--fs-22); }
.page-single__content h3 { font-size: var(--fs-20); }
.page-single__content p { margin-bottom: 16px; }
.page-single__content ul, .page-single__content ol { margin: 0 0 16px 1.2em; padding-left: 1em; list-style: revert; }
.page-single__content li { margin-bottom: 8px; }
.page-single__content a { text-decoration: underline; }

/* --- Blog ---------------------------------------------------------------- */
.blog { padding-top: 140px; }
.blog__head { margin-bottom: 56px; }
.blog__grid { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: var(--gap-md); }
.blog__empty { color: var(--c-text-muted); }

.blog-card { position: relative; display: flex; border-radius: var(--r-card); overflow: hidden; background: var(--c-green-light); transition: transform .18s ease, box-shadow .18s ease; }
.blog-card:hover { transform: translateY(-4px); box-shadow: 0 14px 30px rgba(0,0,0,.12); }
.blog-card__link { display: flex; flex-direction: column; width: 100%; color: inherit; }
.blog-card__media { position: relative; aspect-ratio: 16 / 10; background: var(--c-green-light-50); overflow: hidden; }
.blog-card__img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Category chip on the image — same treatment as the product-card tag. */
.blog-card__cat {
	position: absolute; top: 12px; left: 12px; z-index: 2;
	padding: 4px 10px; border-radius: var(--r-card-sm);
	background: var(--c-chip-overlay); color: var(--c-white);
	font-size: var(--fs-12); font-weight: var(--fw-medium);
}
.blog-card__body { display: flex; flex-direction: column; gap: 12px; padding: 20px; flex: 1; }
.blog-card__title { font-size: var(--fs-20); line-height: var(--lh-tight); }
.blog-card__excerpt { font-size: var(--fs-body); color: var(--c-text-muted); line-height: var(--lh-body); }
.blog-card__foot { margin-top: auto; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-top: 4px; }
.blog-card__date { font-size: var(--fs-12); color: var(--c-text-muted); white-space: nowrap; }

/* "Reviewed by Kushology Experts" trust line — verified badge + label. */
.blog-card__reviewed, .post-single__reviewed {
	display: inline-flex; align-items: center; gap: 6px;
	font-size: var(--fs-12); font-weight: var(--fw-medium); color: var(--c-text);
}
.blog-card__reviewed .icon, .post-single__reviewed .icon { width: 15px; height: 15px; color: #2f7d31; flex: none; }

.blog__pagination { margin-top: 56px; }
.blog__pagination .nav-links { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.blog__pagination a, .blog__pagination .current {
	display: inline-flex; align-items: center; justify-content: center; min-width: 44px; height: 44px; padding: 0 14px;
	border-radius: var(--r-pill); border: 1px solid var(--c-border); font-weight: var(--fw-medium); font-size: var(--fs-14);
}
.blog__pagination .current { background: var(--c-black); color: var(--c-white); border-color: var(--c-black); }
.blog__pagination a:hover { background: var(--c-green-light); }

/* --- Single post --------------------------------------------------------- */
.post-single { padding-top: 140px; max-width: 820px; }
.post-single__crumbs { display: flex; gap: 8px; font-size: var(--fs-14); color: var(--c-text-muted); margin-bottom: 24px; }
.post-single__crumbs a { color: inherit; }
.post-single__crumbs a:hover { text-decoration: underline; }
.post-single__head { margin-bottom: 32px; }
.post-single__cat {
	display: inline-flex; padding: 6px 14px; border-radius: var(--r-pill);
	background: var(--c-green-light); font-size: var(--fs-12); font-weight: var(--fw-medium); margin-bottom: 16px;
}
.post-single__title { font-size: var(--fs-h1); line-height: var(--lh-tight); }
.post-single__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 20px; margin-top: 20px; }
.post-single__date { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-14); color: var(--c-text-muted); }
.post-single__date .icon { width: 15px; height: 15px; flex: none; }
.post-single__reviewed { font-size: var(--fs-14); }
.post-single__reviewed .icon { width: 17px; height: 17px; }

.post-single__hero { margin: 0 0 40px; border-radius: var(--r-panel); overflow: hidden; }
.post-single__hero-img { width: 100%; height: auto; display: block; aspect-ratio: 16 / 9; object-fit: cover; }
.post-single__content { color: var(--c-text-muted); }

/* Below-article expert-review reassurance block. */
.post-single__reviewed-block {
	display: flex; gap: 16px; align-items: flex-start; margin-top: 48px; padding: 24px;
	background: var(--c-green-light-50); border-radius: var(--r-card);
}
.post-single__reviewed-badge { flex: none; display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; background: var(--c-green-light); }
.post-single__reviewed-badge .icon { width: 24px; height: 24px; color: #2f7d31; }
.post-single__reviewed-title { font-weight: var(--fw-medium); margin-bottom: 4px; }
.post-single__reviewed-body { font-size: var(--fs-body); color: var(--c-text-muted); line-height: var(--lh-body); }
.post-single__foot { margin-top: 40px; }

.related { border-top: 1px solid var(--c-divider); }

@media (max-width: 900px) {
	.blog__grid { grid-template-columns: repeat(2, minmax(0,1fr)); gap: 14px; }
	/* 140 to match shop / product / contact / neighborhood singles — this was the
	   only inner template dropping to 120 under the fixed header. */
	.post-single { padding-top: 140px; }
}
@media (max-width: 560px) {
	.blog__grid { grid-template-columns: 1fr; }
}

/* --- Reviews ------------------------------------------------------------ */
.reviews__inner { max-width: 1100px; margin: 0 auto; }
.reviews__fallback { text-align: center; }
.reviews__widget { margin-top: 8px; }
/* One Elfsight app per breakpoint — see template-parts/home/reviews.php. The
   swap is display, not visibility, so the inactive one stays un-intersected and
   its lazy loader never fires. */
.reviews__widget--mobile { display: none; }

/* --- Deals / promo ------------------------------------------------------ */
.deals { padding-top: 140px; }
.deals__head { text-align: center; max-width: 760px; margin: 0 auto 56px; display: flex; flex-direction: column; gap: 16px; align-items: center; }
.deals__intro { color: var(--c-text-muted); }

/* --- Contact ------------------------------------------------------------ */
.contact { padding-top: 140px; }
.contact__head { margin-bottom: 48px; max-width: 900px; }
.contact__head .section-head__body { margin-top: 16px; }
.contact__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-section); align-items: start; }
.contact__details { display: flex; flex-direction: column; gap: 24px; margin: 24px 0 32px; }
.contact__details li { font-size: var(--fs-body); }
.contact__label { display: block; font-size: var(--fs-14); color: var(--c-text-muted); margin-bottom: 4px; }
.contact__details a:hover { text-decoration: underline; }
.contact__map { border-radius: var(--r-card); overflow: hidden; }
.contact__form { background: var(--c-green-light); border-radius: var(--r-panel); padding: 40px; }  /* solid brand green, matching the home newsletter .panel */
.contact__form-title { font-size: var(--fs-card-title); margin-bottom: 24px; }

/* Contact form: mirror the newsletter panel form (.panel .gform_*) so every form
   on the site shares one look — borderless grey pills, fixed height, 2-col field
   grid, hidden labels + placeholders, full-width black pill submit. */
.contact__form .gform_fields { display: grid; grid-template-columns: 1fr 1fr; gap: 16px !important; list-style: none; margin: 0; padding: 0; }
.contact__form .gfield { margin: 0; max-width: 100%; }
/* Full-width fields (name, message) and the footer span both columns; half-width
   fields (phone, email) sit side by side — same as the newsletter grid. */
.contact__form .gfield--width-full, .contact__form .gfield--type-name,
.contact__form .gfield--type-textarea, .contact__form .gform_footer { grid-column: 1 / -1; }
.contact__form .gform_wrapper input:not([type=submit]),
.contact__form .gform_wrapper textarea,
.contact__form .gform_wrapper .ginput_container input {
	width: 100% !important; height: 56px; padding: 16px 24px !important; border-radius: var(--r-pill) !important;
	border: none !important; background: var(--c-grey-light) !important; font-family: inherit; font-weight: var(--fw-medium);
	font-size: var(--fs-body); color: var(--c-text);
}
/* Textarea is the one field that isn't a single-line pill: taller, card radius. */
.contact__form .gform_wrapper textarea { height: auto; min-height: 132px; border-radius: var(--r-card) !important; padding: 16px 24px !important; }
.contact__form .gform_wrapper input::placeholder,
.contact__form .gform_wrapper textarea::placeholder { color: var(--c-text-placeholder); opacity: 1; }
/* Labels hidden (placeholders carry the field name, set in functions.php) — matches
   the newsletter forms. Includes the name "First"/"Last" sub-labels. */
.contact__form .gfield_label, .contact__form .gform_required_legend,
.gform_wrapper .gform-field-label--type-sub { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }
.contact__form .gform_footer { border-top: 1px solid var(--c-divider); margin-top: 16px; padding-top: 32px; }
.contact__form .gform_wrapper .gform_footer input[type=submit],
.contact__form .gform_wrapper .gform_button {
	width: 100% !important; height: var(--btn-h); border-radius: var(--r-pill) !important; border: none !important;
	background: var(--c-black) !important; color: var(--c-white) !important; font-family: inherit;
	font-weight: var(--fw-medium); cursor: pointer;
}

@media (max-width: 900px) {
	.contact__grid { grid-template-columns: 1fr; gap: 40px; }
	.contact__form { padding: 24px; }
}
@media (max-width: 560px) {
	/* Single column on phones (First/Last, Phone/Email stack) — matches the footer
	   newsletter form's collapse so no field pair gets cramped. */
	.contact__form .gform_fields { grid-template-columns: 1fr; gap: 8px !important; }
}

/* --- Single product ----------------------------------------------------- */
.product-single { padding-top: 140px; }
.product-single__crumbs { font-size: var(--fs-14); color: var(--c-text-muted); margin-bottom: 24px; }
.product-single__crumbs a:hover { text-decoration: underline; }
.product-single__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-section); align-items: start; }
/* Grid items default to min-width:auto, so if the info column has wide/unbreakable content it steals the
   whole row and collapses the image panel to 0px (seen on gg4-1g-preroll: cols computed "0px 2216px").
   min-width:0 makes both columns honour the 1fr split; break-word keeps long tokens from forcing width. */
.product-single__grid > * { min-width: 0; }
.product-single__info { overflow-wrap: anywhere; }
.product-single__media {
	border-radius: var(--r-panel); overflow: hidden; aspect-ratio: 1/1;
	background: linear-gradient(to bottom, var(--c-green-light) 48%, var(--c-green-deep-50) 100%);
	/* Flexbox + padding owns the inset (the margin between tile and panel). Percentage sizing on the img
	   itself didn't resolve against the grid's content-sized track, so tall photos rendered taller than the
	   square panel and got clipped at the bottom (overflow:hidden) — "bottom padding gone". */
	display: flex; align-items: center; justify-content: center; padding: 9%;
}
/* Product photos ship on white with the item composed off-centre (vendor/Meadow asset, not croppable in CSS).
   Framing the img as a white rounded tile makes the photo's own white background merge into the tile, so the
   shot reads as an intentional product-on-white card instead of a small item floating on the green panel.
   max-*:100% of the padded flex box (definite via aspect-ratio) → the tile always fits, never clips. */
.product-single__media img {
	max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; box-sizing: border-box;
	background: #fff; border-radius: 20px; padding: 22px;
	box-shadow: 0 8px 24px rgba(20, 46, 22, 0.10);
}
@media (max-width: 640px) {
	.product-single__media { padding: 7%; }
	.product-single__media img { padding: 16px; border-radius: 16px; }
}
.product-single__brand { color: var(--c-text-muted); font-size: var(--fs-14); }
.product-single__title { font-size: var(--fs-h2-2line); margin: 8px 0 16px; }
.product-single__type {
	display: inline-block; padding: 6px 14px; border-radius: var(--r-pill);
	background: var(--c-green-light-50); font-size: var(--fs-12); font-weight: var(--fw-medium);
}
.product-single__price { font-size: 28px; font-weight: var(--fw-medium); margin: 20px 0; }
.product-single__badges { display: flex; gap: 8px; margin: 12px 0; flex-wrap: wrap; }
.product-single__stock { display: inline-flex; align-items: center; gap: 6px; padding: 6px 14px; border-radius: var(--r-pill); font-size: var(--fs-12); font-weight: var(--fw-medium); }
.product-single__stock.in { background: #e6f4d4; color: #4b6b16; }
.product-single__stock.in::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: #6f8f1e; }
.product-single__stock.out { background: #f3f3f3; color: #666; }  /* #888 was 3.2:1 on #f3f3f3; #666 ≈ 5.3:1 */

.product-single__options { margin: 24px 0; }
.product-single__options-label { display: block; font-size: var(--fs-14); font-weight: var(--fw-medium); margin-bottom: 10px; }
.product-single__options-row { display: flex; flex-wrap: wrap; gap: 10px; }
.product-option {
	min-width: 64px; padding: 12px 18px; border-radius: var(--r-pill); border: 1px solid var(--c-border);
	background: var(--c-white); font-family: inherit; font-weight: var(--fw-medium); font-size: var(--fs-14); cursor: pointer;
	transition: border-color .15s ease, background .15s ease, transform .15s ease;
}
.product-option:hover { border-color: var(--c-black); transform: translateY(-1px); }
.product-option.is-active { background: var(--c-green-light); border-color: var(--c-black); }

.product-single__buy { display: flex; gap: 12px; align-items: stretch; margin: 24px 0; flex-wrap: wrap; }
.qty-stepper { display: inline-flex; align-items: center; border: 1px solid var(--c-border); border-radius: var(--r-pill); overflow: hidden; }
.qty-stepper__btn { width: 48px; height: 52px; border: none; background: var(--c-white); font-size: 20px; cursor: pointer; color: var(--c-text); }
.qty-stepper__btn:hover { background: var(--c-green-light-50); }
.qty-stepper__input { width: 48px; height: 52px; border: none; text-align: center; font-family: inherit; font-size: var(--fs-body); }
.product-single__add { flex: 1; min-width: 200px; justify-content: center; border: none; }
.product-single__add.is-added { background: #4b6b16; }
.product-single__add:disabled { opacity: .4; cursor: not-allowed; }

/* Description block. Spacing lives HERE and nowhere else — this rule was being
   contradicted by five appended overrides further down the file, which is why the
   gap under it kept flipping between too much and none at all. */
.product-single__desc {
	color: var(--c-text-muted);
	border-top: 1px solid var(--c-divider);
	margin-top: 0;
	padding-top: 26px;
	padding-bottom: 28px;   /* the space under the copy, before Category */
}
.product-single__desc-title { font-size: var(--fs-20); color: var(--c-text); margin-bottom: 10px; }
/* Spec pairs (Genetics / Breeder / Type / Lead Terps / THC …) parsed out of the description prose,
   presented as a clean label→value list instead of run-on lines. */
.product-single__specs { margin: 20px 0 0; display: grid; }
.product-single__spec {
	display: grid; grid-template-columns: minmax(96px, 32%) 1fr; gap: 16px;
	padding: 12px 0; border-top: 1px solid var(--c-divider); align-items: baseline;
}
/* No bottom border on the last spec — the Category/Brand rows continue the SAME table directly
   below (each row is separated by its own top border), so there's no gap or doubled divider. */
.product-single__spec dt { margin: 0; font-weight: var(--fw-medium); color: var(--c-text); letter-spacing: .01em; }
.product-single__spec dd { margin: 0; color: var(--c-text-muted); }
@media (max-width: 480px) {
	.product-single__spec { grid-template-columns: 1fr; gap: 2px; padding: 10px 0; }
}
/* Category / Brand rows: match the spec list above exactly — same grid, bold label, muted value,
   same dividers and text size — so the whole block reads as one consistent label→value table. */
.product-single__attrs { margin: 0; display: grid; }   /* rows carry their own border-top */
.product-single__attrs li {
	display: grid; grid-template-columns: minmax(96px, 32%) 1fr; gap: 16px;
	padding: 12px 0; border-top: 1px solid var(--c-divider); align-items: baseline;
}
.product-single__attrs li:last-child { border-bottom: 1px solid var(--c-divider); }
.product-single__attr-label { font-weight: var(--fw-medium); color: var(--c-text); }
.product-single__attr-val { display: flex; flex-wrap: wrap; gap: 8px; color: var(--c-text-muted); }
.product-single__attrs a:hover { text-decoration: underline; }
@media (max-width: 480px) {
	.product-single__attrs li { grid-template-columns: 1fr; gap: 2px; padding: 10px 0; }
}

.product-related { margin-top: 80px; }

@media (max-width: 900px) {
	.meadow-wrapper { grid-template-columns: 1fr; }
	.meadow-filters { position: static; }
	.product-single__grid { grid-template-columns: 1fr; gap: 32px; }
}

/* ==========================================================================
   Mobile homepage — Figma "Home" 375 frame (20228:1227), every-detail pass.
   Appended last so these override earlier responsive rules. 900px (not 700)
   so tablet-portrait/responsive previews get the mobile scene too — the
   desktop 1440-canvas hero crops brutally at 768 (Shawn's iPad screenshot);
   900 = the burger-menu breakpoint, so mobile layout tracks the mobile nav.
   ========================================================================== */
.hero__title-pre, .hero__subtitle-more { display: none; }  /* mobile-only copy */

@media (max-width: 900px) {
	:root { --container-pad: 16px; --fs-h1: 40px; --fs-h2: 24px; --fs-h2-2line: 24px; }

	/* --- Header (Frame 10): search LEFT · logo centred · burger RIGHT ------- */
	.site-header__inner { padding-block: 16px; padding-inline: 16px; position: relative; }
	.site-header__logo img, .site-header__logo svg, .custom-logo { height: 24px; width: auto; }
	.site-header__search-btn, .site-header__toggle {
		width: 40px; height: 40px; border-radius: 50%;
		background: var(--c-green-mid); border: none;  /* Figma 20229:472: #b7e166 circles */
		display: grid; place-items: center; padding: 0;
		position: relative;  /* containing block for the hit-area overlay below */
	}
	/* The rule above shrinks both circles (48×48 search / 44×44 toggle on the
	   base rules) to 40×40, under the 44px minimum tap target. Keep Figma's 40px
	   visual and give the 2px back as an invisible overlay, so the hit area is
	   44×44 without redrawing the header. */
	.site-header__search-btn::after, .site-header__toggle::after {
		content: ""; position: absolute; top: 50%; left: 50%; translate: -50% -50%;
		width: 44px; height: 44px; border-radius: 50%;
	}
	/* Figma puts the search circle on the LEFT edge; lift it out of the
	   right-side actions flex without touching the desktop markup. */
	.site-header__search-btn { position: absolute; left: 16px; top: 50%; translate: 0 -50%; }
	/* The hidden nav vacates grid col 1 — pin logo/actions so auto-placement
	   doesn't slide them left. */
	.site-header__logo { grid-column: 2; }
	.site-header__actions { grid-column: 3; }
	.site-header__search-btn .icon, .site-header__search-btn svg { width: 16px; height: 16px; }
	.site-header__toggle-bar, .site-header__toggle-bar::before, .site-header__toggle-bar::after { width: 16px; }
	.site-header__nav { justify-self: start; }

	/* --- Hero scene: the 375×872 mobile canvas (Landing sequence part 5) --- */
	.hero { padding-top: 68.3vw; /* title starts at 256/375 */ padding-bottom: 0; }
	.hero__scene-canvas {
		--scene-scale: calc(100vw / 375px);
		width: 375px; height: 872px;
		left: calc(50% - 187.5px * var(--scene-scale));
	}
	/* Zoomed out + centred (Shawn, ×3): tower centre sits at layer x≈1004, so
	   origin x = (928.5 − 1004k)/(1−k) puts it on the canvas centreline at
	   scale k; origin y ≤ 137/(1−k) keeps the photo's top edge above the canvas.
	   Both layers fade out ~canvas y200→270 (before the title, per Figma) — the
	   mask stops are in ELEMENT coords, so they're mapped through the transform:
	   el = o + (canvas + 137 − o)/k. The un-transformed grads wash no longer
	   covers the zoomed photo, so BOTH layers carry the mask (not just bridge2). */
	.hero__scene-bridge, .hero__scene-bridge2 {
		/* k=.45 with translate/origin solved to keep the tower top at the same
		   canvas y (~113) and centred ("maintain this position, zoom in a bit").
		   The translate drops the photo's top edge into view, so the mask also
		   fades the TOP; fade-out still completes ~canvas y270, before the title. */
		transform: translateY(55px) scale(.5); transform-origin: 853px 220px;
		-webkit-mask-image: linear-gradient(180deg, transparent 0, #000 21%, #000 25%, transparent 35%);
		mask-image: linear-gradient(180deg, transparent 0, #000 21%, #000 25%, transparent 35%);
	}
	.hero__scene-bridge  { left: -741px; top: -137px; }
	/* NO wash tint here (unlike the desktop short-wide branch) — over the
	   zoomed mobile crop it turns the tower's red to olive. */
	.hero__scene-bridge2 { left: -741px; top: -135px;
		background: url(../img/prepage-bridge.webp) center / cover no-repeat;
	}
	/* Figma mobile: the scene is fully WHITE below the bridge (~canvas y270,
	   before the title) — the desktop mask-fade left the green wash showing
	   there. Painted on the grads layer: above the bridge photo, below the
	   clouds slab. Stops in grads-box coords (top −155, h 1547):
	   canvas y150 → 19.7%, y270 → 27.5%. */
	.hero__scene-grads   { left: -908px; top: -155px;
		background:
			linear-gradient(180deg, rgba(255,255,255,0) 19.7%, #ffffff 27.5%),
			linear-gradient(180deg, rgba(255,255,255,0) 38.3%, #ffffff 75.4%),
			linear-gradient(180deg, #d8f4a0 9.76%, rgba(216,244,160,0) 61.97%);
	}
	/* Fog band y165–315 (nudged down per Shawn); widen past the ±60px drift and
	   fade the slab's edges so the squeezed image never prints a hard rectangle. */
	.hero__scene-clouds  { left: -121px; top: 165px; width: 616px; height: 150px;
		-webkit-mask-image: linear-gradient(180deg, transparent 0, #000 30%, #000 65%, transparent 100%);
		mask-image: linear-gradient(180deg, transparent 0, #000 30%, #000 65%, transparent 100%);
	}
	.hero__scene-wordmark { top: 32.3vw; width: 100vw; }
	.hero__scene::after { height: 18vh; }

	/* Mobile geometry for the animated scene video: the portrait file matches
	   the 375×872 canvas. */
	.hero__scene-video {
		left: 0; width: 100%; height: 232.54vw; /* 872/375 */
	}

	/* --- Hero copy: centred, mobile copy variants -------------------------- */
	.hero__title-pre { display: block; }  /* Figma: "Kushology" gets its own line */
	.hero__subtitle-more { display: inline; }
	.hero__inner { flex-direction: column; align-items: center; gap: 32px; }
	/* align-self: stretch — .hero__inner is align-items:center here, which makes
	   .hero__intro a shrink-to-fit flex item; the H1 and button row then measured
	   the full container while the subtitle centred inside a narrower box. */
	.hero__intro { text-align: center; max-width: none; align-self: stretch; }
	.hero__title { font-size: 40px; line-height: 1.3; }
	/* The old flat 343px cap was measured off the 375px Figma canvas, so on every
	   wider phone it undercut the container: at 390px the H1 and button row ran
	   16→374 while the subtitle only ran 23.5→366.5 — centred, but 15px narrower
	   than everything around it, which is what read as "off-centre".
	   min(560px, 100%) tracks the container at phone widths (so the three blocks
	   share one measure) and only starts capping near tablet, where 100% would
	   otherwise give 14px text an unreadably long line. */
	.hero__subtitle { font-size: var(--fs-body); margin: 16px auto 0; max-width: min(560px, 100%); }
	.hero__actions { width: 100%; gap: 8px; flex-wrap: nowrap; }
	.hero__actions .btn {
		flex: 1 1 0; justify-content: center; padding: 9px 0; font-size: var(--fs-14); min-width: 0;
	}
	.hero__actions .btn .icon { width: 16px; height: 16px; }
	.hero__carousel { margin-top: 48px; }

	/* --- Carousels: 8px gaps everywhere ------------------------------------ */
	.hscroll { gap: 8px; }
	.hscroll--bleed::after { flex-basis: calc(var(--bleed-inset) - 8px); }

	/* Hero mini cards: 184×240 (Frame 27) */
	.pcard-mini { flex: 0 0 184px; width: 184px; min-height: 240px; padding: 16px; }
	.pcard-mini::after { content: none; }  /* Figma mobile cards: no watermark */
	.pcard-mini__media { min-height: 111px; }
	.pcard-mini__img { width: 111px; height: 111px; margin: 20px auto 8px; }
	/* Figma truncates names to one line ("Elektra Ice Smalls 28…") */
	.pcard-mini__name { font-size: var(--fs-14); display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
	.pcard-mini__meta { font-size: var(--fs-12); }
	/* overflow: visible releases the base rule's clip so the hit-area overlay can
	   escape the 28px circle. Safe: the clip only existed to hide the plugin's
	   "Adding…" label, and font-size: 0 (kept here) already collapses it. */
	.pcard-mini__add { width: 28px; height: 28px; top: 16px; right: 16px; font-size: 0; overflow: visible; }  /* font stays 0 (see base rule); + sized via ::before below */
	.pcard-mini__add::before { font-size: 18px; }
	/* 28px is Figma's circle but well under the 44px minimum tap target — grow
	   only the hit area with a transparent centred overlay, leaving the drawn
	   button untouched. */
	.pcard-mini__add::after {
		content: ""; position: absolute; top: 50%; left: 50%; translate: -50% -50%;
		width: 44px; height: 44px; border-radius: 50%;
	}

	/* --- Categories (Frame 30): 240×280 tiles, no heading ------------------ */
	.tile--category { flex-basis: 240px; width: 240px; min-height: 280px; }
	.tile__title { font-size: var(--fs-body); }

	/* --- Progress bars: full container width ------------------------------- */
	.progressbar { width: 100%; }
	.carousel-controls { margin-top: 24px; }
	.carousel-controls .chevrons { display: none; }  /* Figma mobile: bar only */

	/* --- Featured (Frame 26): centred heading, 3×3 grid of 9, 8px gaps ------ */
	.featured .section-head, .featured h2 { text-align: center; }
	.featured__grid { grid-template-columns: repeat(3, 1fr); gap: 24px 8px; margin: 40px 0 48px; }  /* Figma 20228:1411: 24px row / 8px col */
	.featured__grid .pcard:nth-child(n+10) { display: none; }  /* Figma mobile shows 9 */
	.pcard::before { content: none; }  /* Figma mobile tiles: no watermark */
	/* Figma 20228:1416 mobile: 10px white on rgba(0,0,0,.3), 6px radius, 4/6 padding, top-left. */
	.pcard__tag { top: 8px; left: 8px; right: auto; height: auto; padding: 4px 6px; font-size: 10px; border-radius: 6px; }
	.featured .btn { width: 100%; justify-content: center; padding: 9px 0; font-size: var(--fs-14); }

	/* --- Band (Frame 3): tight panel, 16px centred copy, inverted buttons --- */
	.band { min-height: 334px; width: calc(100% - 16px); padding: 48px 24px; gap: 32px; }
	/* The desktop scrim is percentage-based over an 800px band; squeezed into 334px
	   the copy lands on the brightest part of the storefront photo (the lit green
	   sign) and the gradient stops no longer cover it. Flat extra layer on mobile
	   only, so the desktop treatment is untouched. */
	.band::after {
		background:
			linear-gradient(180deg, rgba(0,0,0,0.35) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0.45) 100%),
			linear-gradient(rgba(0,0,0,0.62), rgba(0,0,0,0.62));
	}
	.band__title { font-size: var(--fs-body); font-weight: var(--fw-medium); }
	/* Figma 20228:1497/1500: Order Now = plain white .btn (base style already
	   matches), Shop Deals = glass ghost. Markup moved off .btn--primary — keep
	   these selectors in sync with template-parts/home/about.php. */
	.band .btn { flex: 0 0 auto; justify-content: center; padding: 9px 20px; font-size: var(--fs-14); }
	.band .btn .icon { width: 16px; height: 16px; }
	.band .btn--ghost { border-color: rgba(255,255,255,.2); }

	/* --- Deals (Frame 38): 240×240 tiles ----------------------------------- */
	.tile--location, section[aria-label="Deals, discounts and rewards"] .tile {
		flex-basis: 240px; width: 240px; min-height: 240px;
	}

	/* --- Around the city (Frame 32): full-width 343×400 cards -------------- */
	section[aria-label="Around the city"] .tile {
		flex-basis: calc(100vw - 32px); width: calc(100vw - 32px); min-height: 400px;
	}

	/* --- Section rhythm (Frames 30/32/37/38): 56px block padding, stacked
	   head with 12px title→body gap, 12px body, 40px head→carousel ---------- */
	.section { padding-block: 56px; }
	.section-head { flex-direction: column; align-items: flex-start; gap: 12px; }
	.section-head__body { font-size: var(--fs-12); max-width: none; }
	.section .card-row { margin-top: 40px !important; }  /* beats the inline style */

	/* --- Recommend / section buttons: 2-up, 40px ---------------------------- */
	.section .btn { font-size: var(--fs-14); }

	/* --- Newsletter panels (home Frame 76 + weed-deals loop 20228:2195) ----- */
	.panel { width: calc(100% - 16px); padding: 24px 16px; border-radius: 24px; }
	.panel--newsletter { gap: 24px; }
	.panel__head { gap: 12px; }
	.panel__body { font-size: var(--fs-12); }
	.panel__row { gap: 16px; }  /* image → form card (Figma 385→401) */
	.panel__media { border-radius: 12px; }
	.panel__media img { height: auto; aspect-ratio: 327 / 240; }
	.panel--loop { border-radius: 16px; }
	/* Form card (Figma 20228:1568): p16 r12, fields 40px/gap 8, divider gap 16,
	   button → legal gap 24. */
	.signup { padding: 16px; border-radius: 12px; gap: 16px; justify-content: flex-start; }
	.signup__fields { gap: 8px; }
	.signup__row { flex-direction: column; gap: 8px; }
	/* desktop's flex:1 zeroes flex-basis — in the column stack that collapses
	   the fields to half height (height loses to flex-basis on the main axis) */
	.signup__row > * { flex: none; }
	.field { padding: 0 16px; }
	.signup .btn { padding: 9px 0; font-size: var(--fs-14); }
	.signup .btn .icon { width: 16px; height: 16px; }
	.legal { font-size: var(--fs-12); }
	/* Gravity Forms variant of the same card (Figma 20228:1568): stacked
	   40px fields, gap 8, divider gaps 16/16. */
	.panel__form:has(.gform_wrapper) { padding: 16px; border-radius: 12px; gap: 16px; }
	.panel .gform_fields { grid-template-columns: 1fr; gap: 8px !important; }
	.panel .gform_wrapper input:not([type=submit]),
	.panel .gform_wrapper .ginput_container input { height: 40px; padding: 0 16px !important; font-size: var(--fs-12); }
	.panel .gform_footer { margin-top: 8px; padding-top: 16px; }
	.panel .gform_wrapper .gform_footer input[type=submit],
	.panel .gform_wrapper .gform_button { height: 40px; font-size: var(--fs-14); }

	/* The Figma mobile homepage had no testimonials section, so this was hidden.
	   It now carries a dedicated mobile Elfsight app, so the section shows and the
	   two widgets swap. */
	.reviews__widget--desktop { display: none; }
	.reviews__widget--mobile { display: block; }

	/* --- Section tints: mobile frame has its OWN ellipse geometry ------------
	   (nodes 20228:1376/1407/1537/1587/1620; same #D8F4A0 @.3, σ100).
	   Gradient RADII = ellipse radius + 2σ — same convention as the desktop
	   tints (radial-gradient's two lengths are semi-axes, not box sizes);
	   plateau ≈ (r−2σ)/(r+2σ); Y anchored via calc(f% + (512 − f·1024)px) to
	   match the ±512px pseudo extension. */
	/* Categories E4 1095×869 @ (70,−333) in 442-tall frame → centre (617,101) */
	.section--glow-categories::before {
		background-image: radial-gradient(747px 634px at calc(50% + 430px) calc(23% + 277px), rgba(216,244,160,0.3) 46%, rgba(216,244,160,0) 100%);
	}
	/* Featured E4 1095×869 @ (67,−46) in 654-tall frame → centre (614,388);
	   the desktop right-edge ellipse (E5) sits fully outside the mobile frame. */
	.section--glow-both::before {
		background-image: radial-gradient(747px 634px at calc(50% + 427px) calc(59.4% - 96px), rgba(216,244,160,0.3) 46%, rgba(216,244,160,0) 100%);
	}
	/* Deals E4 @ x628 — entirely outside the 375 frame, clipped: no tint. */
	.section--glow-deals::before { background-image: none; }
	/* Recommend E6 1366×556 @ (−495,0) — but in the Figma frame a WHITE clouds
	   layer (footer-clouds, y187↓) covers the ellipse's lower two thirds, so
	   the section RENDERS white with green only peeking at the top (Shawn:
	   "only this part"). Match the render, not the raw ellipse: the tint hugs
	   the section top and is gone before the heading. */
	.section--glow-recommend::before {
		background-image: radial-gradient(883px 320px at 50% 512px, rgba(216,244,160,0.3) 25%, rgba(216,244,160,0) 100%);
	}
	/* Around-city E7 1366×869 @ (−28,148) in 778-tall frame → centre (655,582) */
	.section--glow-city::before {
		background-image: radial-gradient(883px 634px at calc(50% + 468px) calc(74.9% - 255px), rgba(216,244,160,0.3) 55%, rgba(216,244,160,0) 100%);
	}
	/* FAQ E6 1366×869 @ (−801,533) in 1062-tall frame → centre (−118,967) */
	.section--glow-faq::before {
		background-image: radial-gradient(883px 634px at calc(50% - 306px) calc(91.1% - 421px), rgba(216,244,160,0.3) 55%, rgba(216,244,160,0) 100%);
	}

	/* --- Footer (Frame 34): signup full row, Shop | About Us 2-col, Visit full */
	.site-footer { padding: 48px 16px 0; }
	.site-footer__top { grid-template-columns: 1fr 1fr; gap: 40px 8px; }
	.site-footer__signup, /* Was spanning the full row under the 3-column layout; it is a normal column now. */
.site-footer__visit { grid-column: auto; }

	/* --- FAQ (Frame 37) ------------------------------------------------------ */
	.faq { grid-template-columns: 1fr; gap: 40px; }
	.faq__q { font-size: var(--fs-body); gap: 12px; }
	.faq__toggle { flex: 0 0 40px; width: 40px; height: 40px; font-size: 16px; }
	.faq__item { padding: 16px 0; }
	.faq__a { font-size: var(--fs-12); }

	/* --- Footer form + placeholder .field: 40px fields ----------------------
	   (panel GF inputs get theirs from the panel rules above — keep one
	   source per form, no overlapping duplicates) */
	.site-footer .gform_wrapper input:not([type=submit]),
	.site-footer .gform_wrapper .ginput_container input,
	.field {
		height: 40px; font-size: var(--fs-12);
	}
}

/* ==========================================================================
   Weed Deals page (Figma 20228:476)
   ========================================================================== */
/* --- Hero (20228:1026): full-bleed photo panel below the header ---------- */
.wd-hero { padding: 96px 8px 0; }
.wd-hero__panel {
	position: relative; overflow: hidden; border-radius: var(--r-panel);
	height: min(calc(100svh - 104px), 936px); min-height: 560px;
	background: #1a1d16;
}
.wd-hero__bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.wd-hero__panel::after {
	content: ""; position: absolute; inset: 0; z-index: 1;
	background:
		linear-gradient(180deg, rgba(0,0,0,0) 62.3%, rgba(0,0,0,0.9) 94%),
		linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5));
}
.wd-hero__content {
	position: absolute; left: 48px; right: 48px; bottom: 72px; z-index: 2;
	display: flex; align-items: flex-end; gap: 48px; color: var(--c-white);
}
.wd-hero__copy { flex: 1; display: flex; flex-direction: column; gap: 24px; }
.wd-hero__title { font-size: var(--fs-h1); }
.wd-hero__lede { max-width: 850px; color: var(--c-text-on-dark-muted); }
.wd-hero__actions { display: flex; gap: var(--gap-xs); flex: none; }
.wd-hero .btn--ghost { background: rgba(255,255,255,0.2); }

/* --- Weekly discounts switcher (20228:751) -------------------------------- */
.wd-weekly__head { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--gap-lg); }
.wd-weekly__title { max-width: 628px; }
.wd-weekly__intro {
	width: 664px; max-width: 100%; display: flex; flex-direction: column; gap: 24px;
	align-items: flex-start; font-size: var(--fs-body); color: var(--c-text-muted);
}
.wd-weekly__grid { display: grid; grid-template-columns: 536px 1fr; gap: 80px; margin-top: 64px; align-items: stretch; }
.wd-weekly__left { display: flex; flex-direction: column; gap: 80px; }
.wd-deals { border-right: 1px solid var(--c-border); }
.wd-deals__item {
	display: block; width: 100%; text-align: left; padding: 16px 0;
	background: none; border: none; border-right: 2px solid transparent; cursor: pointer;
	font-family: inherit; font-size: var(--fs-20); line-height: normal; color: var(--c-text-muted);
	transition: color .15s ease;
}
.wd-deals__item:hover { color: var(--c-text); }
/* #97cf26 = the Figma active-rail green (solid form of --c-green-deep-50). */
.wd-deals li { margin-right: -1px; }
.wd-deals__item.is-active { color: var(--c-text); font-weight: var(--fw-medium); border-right-color: #97cf26; }
.wd-note {
	position: relative; overflow: hidden; margin-top: auto;
	display: flex; flex-direction: column; gap: 12px; padding: 16px;
	border-radius: var(--r-card-sm); border: 1px solid rgba(151,207,38,0.1);
	background:
		radial-gradient(560px 270px at 35% 0%, rgba(216,244,160,0.55), rgba(216,244,160,0) 70%),
		rgba(151,207,38,0.1);
}
.wd-note__head { display: flex; gap: 8px; align-items: center; font-weight: var(--fw-medium); font-size: 18px; }
.wd-note__head .icon { width: 20px; height: 20px; flex: none; color: #97cf26; }
.wd-note__body { font-size: var(--fs-body); color: var(--c-text-muted); }
.wd-showcase {
	position: relative; overflow: hidden; border-radius: var(--r-card);
	background: var(--c-green-light-50); min-height: 560px; margin: 0;
}
.wd-showcase__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.wd-showcase::after {
	content: ""; position: absolute; inset: 0; z-index: 1;
	background: linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0.8) 76.5%);
}
.wd-showcase__cap {
	position: absolute; left: 40px; right: 40px; bottom: 40px; z-index: 2; max-width: 457px;
	display: flex; flex-direction: column; gap: 8px; color: var(--c-white);
}
.wd-showcase__title { font-size: 26px; font-weight: var(--fw-medium); line-height: normal; }
.wd-showcase__line { font-size: var(--fs-14); line-height: var(--lh-body); }

/* --- Why shop deals (20228:785): rotated product collage ------------------ */
/* No overflow:hidden — it hard-clipped the tint at the section edges. The
   global html/body overflow-x clip still guards the extra-wide clouds layer,
   and the clouds fit inside the section vertically. */
.wd-why { position: relative; padding: 0 48px 120px; text-align: center; }
/* Figma 20228:786 in Frame 36: E6 683×434 σ100 ellipse, centred, 282px from
   the section top. Painted on a box extended 512px above/below (same recipe
   as the homepage glows) so the tint BLEEDS into the neighbouring sections
   instead of cutting off at the boundary; z:-1 keeps it behind content. */
.wd-why::before {
	content: ""; position: absolute; top: -512px; bottom: -512px; left: 50%; width: 100vw;
	transform: translateX(-50%); z-index: -1; pointer-events: none;
	background: radial-gradient(883px 634px at 50% 794px, rgba(216,244,160,0.3) 55%, rgba(216,244,160,0) 100%) no-repeat;
}
.wd-why__collage { position: relative; height: 450px; z-index: 1; }
.wd-why__card { position: absolute; left: 50%; overflow: hidden; background: var(--c-white); }
.wd-why__card img { width: 100%; height: 100%; object-fit: cover; }
.wd-why__card--1 { width: 259px; height: 324px; border-radius: 13px; top: 79px; transform: translateX(calc(-50% - 275px)) rotate(-7.88deg); }
.wd-why__card--2 { width: 272px; height: 340px; border-radius: 14px; top: 17px; transform: translateX(calc(-50% - 32px)); }
.wd-why__card--3 { width: 285px; height: 357px; border-radius: 14px; top: 62px; transform: translateX(calc(-50% + 232px)) rotate(5.64deg); }
.wd-why__clouds {
	position: absolute; left: 50%; top: 187px; transform: translateX(-50%);
	width: max(133%, 1920px); max-width: none; height: 766px; object-fit: cover; object-position: bottom;
	z-index: 1; pointer-events: none;
	-webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 200px);
	mask-image: linear-gradient(to bottom, transparent 0, #000 200px);
	will-change: transform;
	animation: kush-clouds-drift 7s ease-in-out infinite alternate;
}
.wd-why__body { position: relative; z-index: 2; max-width: 754px; margin: -2px auto 0; display: flex; flex-direction: column; gap: 40px; align-items: center; }
.wd-why__title { font-size: var(--fs-h2-2line); }
.wd-why__text { font-size: var(--fs-body); color: var(--c-text-muted); margin-top: -16px; }
.wd-why__readmore {
	background: none; border: none; padding: 0; cursor: pointer;
	font: inherit; font-weight: var(--fw-medium); color: var(--c-text); text-decoration: underline;
}
.wd-why__actions { display: flex; gap: var(--gap-xs); justify-content: center; }

/* --- Stay in the loop (20228:810): green newsletter panel variant --------- */
.panel--loop .panel__body { max-width: none; }

/* --- Responsive ------------------------------------------------------------ */
@media (max-width: 1100px) {
	.wd-weekly__grid { grid-template-columns: 1fr; gap: 40px; }
	.wd-weekly__left { gap: 40px; }
	.wd-showcase { min-height: 420px; }
}
/* Mobile (Figma 20228:1777, 375 frame). */
@media (max-width: 900px) {
	/* Hero (20228:1778): stacked copy, half-width 40px buttons. */
	.wd-hero { padding: 72px 8px 0; }
	.wd-hero__panel { height: 732px; min-height: 0; }
	.wd-hero__content { flex-direction: column; align-items: stretch; gap: 32px; left: 16px; right: 16px; bottom: 40px; }
	.wd-hero__title { font-size: 32px; }
	.wd-hero__lede { font-size: var(--fs-body); }
	.wd-hero__actions .btn { flex: 1; }
	/* 40px-tall mobile pills with 16px arrows, per the 375 frame. */
	.wd-hero__actions .btn, .wd-weekly__intro .btn, .wd-why__actions .btn {
		height: 40px; padding-block: 0; justify-content: center; font-size: var(--fs-14);
	}
	.wd-hero__actions .icon-arrow, .wd-weekly__intro .icon-arrow, .wd-why__actions .icon-arrow {
		width: 16px; height: 16px;
	}

	/* Weekly (20228:1818): tabs scroll horizontally, image then note card.
	   No green tints on the mobile Weed Deals page (Shawn): weekly, why-shop,
	   and FAQ (whose ±512px bleed is what washes the loop panel, 20228:2195). */
	.wd-weekly { padding-block: 48px; }
	.section--glow-wd-weekly::before, .wd-why::before,
	.section--glow-wd-faq::before { background-image: none; }
	.wd-weekly__head { flex-direction: column; gap: 12px; }
	.wd-weekly__title { max-width: none; font-size: 24px; }
	.wd-weekly__intro { width: 100%; gap: 24px; font-size: var(--fs-12); }
	.wd-weekly__intro .btn { width: 100%; }
	.wd-weekly__grid { display: flex; flex-direction: column; gap: 16px; margin-top: 40px; }
	.wd-weekly__left { display: contents; }
	.wd-deals {
		display: flex; gap: 24px; overflow-x: auto; overflow-y: hidden;
		border-right: 0; border-bottom: 1px solid var(--c-border);
		scrollbar-width: none;
		/* The strip scrolls but its scrollbar is hidden, so at 390px the later tabs
		   just ended at the viewport edge and read as clipped rather than scrollable.
		   The fade (plus trailing padding, so the last tab clears it) signals more. */
		padding-right: 32px;
		-webkit-mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent 100%);
		mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent 100%);
	}
	.wd-deals::-webkit-scrollbar { display: none; }
	.wd-deals li { flex: none; margin: 0 0 -1px; }
	.wd-deals__item {
		width: auto; padding: 16px 0; white-space: nowrap; font-size: var(--fs-14);
		border-right: 0; border-bottom: 2px solid transparent;
	}
	.wd-deals__item.is-active { border-right-color: transparent; border-bottom-color: #97cf26; }
	.wd-showcase { order: 2; min-height: 0; height: 320px; border-radius: 12px; }
	.wd-showcase__cap { left: 16px; right: 16px; bottom: 16px; }
	.wd-showcase__title { font-size: var(--fs-body); }
	.wd-showcase__line { font-size: var(--fs-12); }
	.wd-note { order: 3; margin-top: 0; border-radius: 12px; }
	.wd-note__head { font-size: var(--fs-body); }
	.wd-note__head .icon { width: 16px; height: 16px; }
	.wd-note__body { font-size: var(--fs-12); }

	/* Why (20228:2219): mini collage, stacked copy, full-width button pair.
	   No fog on mobile — the desktop cloud bleed floats (z1) over the loop
	   panel's heading below and washes it out. */
	.wd-why { padding: 0 16px 64px; }
	.wd-why__clouds { display: none; }
	.wd-why__collage { height: 200px; }
	.wd-why__card--1 { width: 107px; height: 133px; border-radius: 6px; top: 34px; transform: translateX(calc(-50% - 108px)) rotate(-7.88deg); }
	.wd-why__card--2 { width: 114px; height: 143px; border-radius: 6px; top: 0; transform: translateX(calc(-50% - 6px)); }
	.wd-why__card--3 { width: 114px; height: 143px; border-radius: 6px; top: 13px; transform: translateX(calc(-50% + 119px)) rotate(5.64deg); }
	.wd-why__title { font-size: 24px; }
	.wd-why__text { font-size: var(--fs-12); }
	.wd-why__actions { width: 100%; }
	.wd-why__actions .btn { flex: 1; }

	/* Stay in the loop (20228:2195): Figma breaks the title after "Loop". */
	.panel--loop .panel__title { max-width: 220px; }
}

/* ===========================================================================
   Neighborhoods guide — archive-neighborhoods.php
   Rebuild of kushology.com/neighborhoods/. Reuses .btn, .section, .section-head,
   .tile (home/categories), .faq (food pairings) and .band (discover CTA); the
   .nbh-* rules below add the sections that have no homepage equivalent.
   =========================================================================== */

/* Outlined pill for LIGHT backgrounds (.btn--ghost is white-on-dark only). */
.btn--outline { background: transparent; color: var(--c-black); border: 1.5px solid var(--c-black); }

/* Hero — full-bleed lime band. Top padding clears the fixed header (cf .deals). */
.nbh-hero {
	position: relative;
	/* No bottom step. It stacked with .nbh-cats' padding-top AND the --gap-lg on
	   #categories inside it for a 256px void under the hero buttons; the two
	   below already add up to the standard 120px section gap. */
	padding: 184px 0 0;
	/* Fade to TRANSPARENT, not white. Ending on an opaque white hid the category
	   section's green glow, which then reappeared at full strength the pixel the
	   hero ended — green → white → green, reading as a seam across the page
	   (measured: tint 4 at y=580, 18 at y=600). Fading out instead lets whatever
	   is underneath — plain white on the left, the glow on the right — carry
	   through continuously. rgba() of the same green, not `transparent`, so the
	   interpolation doesn't dip through grey. */
	background: linear-gradient(180deg, #cdee8f 0%, var(--c-green-light) 55%, rgba(216, 244, 160, 0) 100%);
}
.nbh-hero__inner { display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--gap-lg); }
.nbh-hero__title { font-size: var(--fs-h1); line-height: var(--lh-tight); max-width: 16ch; }
.nbh-hero__actions { display: flex; gap: var(--gap-sm); flex-wrap: wrap; justify-content: center; }

/* Shop by Category — heading above the reused categories carousel. The heading
   sits in its own top padding; the carousel section's own top padding is pulled
   in so the heading and cards read as one block (was: heading crammed on the
   hero with a 120px void below it). */
/* The hero's own bottom padding already separates it from what follows; a full
   --section-py on top of that put 256px of empty page between the hero buttons
   and "Shop by Category". The two read as one intro, so the following section
   uses the smaller step. */
.nbh-cats { padding-top: var(--section-py-sm); }
.nbh-cats .section-head { justify-content: center; align-items: center; text-align: center; }
.nbh-cats #categories { padding-top: var(--gap-lg); }

/* Prose bands (mission, why-us) — narrow readable column. */
.nbh-prose { max-width: 860px; }
.nbh-prose > .h2 { margin-bottom: var(--gap-md); }
.nbh-prose p { color: var(--c-text-muted); line-height: var(--lh-body); }
.nbh-prose p + p { margin-top: var(--gap-md); }
.nbh-prose__actions { display: flex; gap: var(--gap-sm); flex-wrap: wrap; margin-top: var(--gap-lg); }

/* Areas served — responsive card grid; names deep-link when a CPT page exists. */
.nbh-areas__grid {
	list-style: none; margin: var(--gap-lg) 0 0; padding: 0;
	display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap-md);
}
.nbh-area {
	display: flex; flex-direction: column; gap: 8px;
	background: var(--c-white); border: 1px solid var(--c-border);
	border-radius: var(--r-card); padding: var(--gap-md);
	transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
/* Only cards that actually have a page are interactive. The hover used to apply
   to every card, so the 10 areas with no page yet looked clickable and weren't. */
.nbh-area--linked { position: relative; cursor: pointer; }
.nbh-area--linked:hover { transform: translateY(-3px); box-shadow: 0 14px 30px rgba(0,0,0,0.08); border-color: var(--c-green-mid); }
/* Stretched link: the whole card is the click target, but the anchor stays on the
   title so screen readers and crawlers still get meaningful link text. */
.nbh-area--linked .nbh-area__name a::after { content: ""; position: absolute; inset: 0; z-index: 1; }
/* Keyboard parity — focusing the title rings the whole card, matching the hover. */
.nbh-area--linked:has(.nbh-area__name a:focus-visible) {
	outline: 2px solid var(--c-green-mid); outline-offset: 2px; border-color: var(--c-green-mid);
}
.nbh-area--linked .nbh-area__name a:focus-visible { outline: none; }
.nbh-area__name { font-size: var(--fs-20); font-weight: var(--fw-medium); }
.nbh-area__name a { color: inherit; text-decoration: none; }
.nbh-area--linked:hover .nbh-area__name a { text-decoration: underline; }
.nbh-area__desc { font-size: var(--fs-body); color: var(--c-text-muted); line-height: var(--lh-body); }
/* No-description entries read as "also serving" chips so the grid stays tidy. */
.nbh-area--bare { justify-content: center; text-align: center; background: var(--c-green-light-50); border-color: transparent; }

/* Local landmarks — two-up list with pin badges. */
.nbh-landmarks__grid {
	list-style: none; margin: var(--gap-lg) 0 0; padding: 0;
	display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gap-md) var(--gap-lg);
}
.nbh-landmark { display: flex; gap: var(--gap-sm); align-items: flex-start; }
.nbh-landmark__pin {
	flex: 0 0 auto; display: grid; place-items: center;
	width: 40px; height: 40px; border-radius: 50%;
	background: var(--c-green-light); color: var(--c-black);
}
.nbh-landmark__pin .icon { width: 18px; height: 18px; }
.nbh-landmark__place { font-size: var(--fs-20); font-weight: var(--fw-medium); margin-bottom: 4px; }
.nbh-landmark__tip { font-size: var(--fs-14); color: var(--c-text-muted); line-height: var(--lh-body); }
.nbh-landmarks__note, .nbh-pairings__note, .nbh-rules__note {
	max-width: 860px; margin-top: var(--gap-lg);
	font-size: var(--fs-body); color: var(--c-text-muted); line-height: var(--lh-body);
}

/* Ways to experience SF — 2x2 numbered lime cards. */
.nbh-exp__grid { margin-top: var(--gap-lg); display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--gap-md); }
.nbh-exp__card {
	display: flex; flex-direction: column; gap: 12px;
	background: var(--c-green-light); border-radius: var(--r-panel); padding: var(--gap-lg);
}
.nbh-exp__num { font-size: var(--fs-card-title); font-weight: var(--fw-medium); color: rgba(0,0,0,0.32); line-height: 1; }
.nbh-exp__title { font-size: var(--fs-22); font-weight: var(--fw-medium); }
.nbh-exp__body { font-size: var(--fs-body); color: var(--c-text-muted); line-height: var(--lh-body); }

/* Food pairings — homepage FAQ layout (.faq 2-col grid). Left column wraps the
   heading + intro (grid child 1); .faq__list is grid child 2. */
.nbh-pairings .faq__intro-body { margin-top: var(--gap-md); max-width: 480px; font-size: var(--fs-body); color: var(--c-text-muted); line-height: var(--lh-body); }
.nbh-pairing__pair { font-weight: var(--fw-medium); color: var(--c-black); margin-bottom: 8px; }
.nbh-pairing__pair span { color: var(--c-text-muted); font-weight: var(--fw-regular); }

/* Etiquette — checklist rows. */
.nbh-rules__list { list-style: none; margin: var(--gap-lg) 0 0; padding: 0; display: grid; gap: var(--gap-sm); max-width: 900px; }
.nbh-rule { display: flex; gap: var(--gap-sm); align-items: flex-start; font-size: var(--fs-body); color: var(--c-text); line-height: var(--lh-body); }
.nbh-rule .icon { flex: 0 0 auto; width: 24px; height: 24px; color: #6bbf1f; margin-top: 1px; }

/* Discover — compact dark CTA band + contact meta (overrides tall .band). */
.nbh-discover__band {
	min-height: 0; padding: 64px 48px; background: var(--c-near-black);
	text-align: left; flex-direction: row; flex-wrap: wrap; align-items: stretch;
	justify-content: space-between; gap: var(--gap-lg);
}
.nbh-discover__copy { position: relative; z-index: 2; flex: 1 1 520px; max-width: 720px; }
.nbh-discover__copy .band__title { text-align: left; margin-bottom: var(--gap-md); }
.nbh-discover__copy p { color: var(--c-text-on-dark-muted); line-height: var(--lh-body); }
.nbh-discover__copy p + p { margin-top: var(--gap-md); }
.nbh-discover__band .band__actions { margin-top: var(--gap-lg); justify-content: flex-start; }
.nbh-discover__meta {
	position: relative; z-index: 2; align-self: center;
	flex: 1 1 260px; list-style: none; margin: 0; padding: 0;
	display: flex; flex-direction: column; gap: var(--gap-md);
}
.nbh-discover__meta li { display: flex; gap: 12px; align-items: flex-start; color: var(--c-text-on-dark); }
.nbh-discover__meta .icon { flex: 0 0 auto; width: 20px; height: 20px; color: var(--c-green-light); margin-top: 2px; }
.nbh-discover__meta a { color: inherit; text-decoration: none; }
.nbh-discover__meta a:hover { text-decoration: underline; }

@media (max-width: 1100px) {
	.nbh-areas__grid { grid-template-columns: repeat(2, 1fr); }
	.nbh-landmarks__grid, .nbh-exp__grid { grid-template-columns: 1fr; }
}
@media (max-width: 900px) {
	.nbh-hero { padding: 128px 0 0; }
	.nbh-discover__band { flex-direction: column; padding: 40px 24px; }
	/* Reset the flex bases. They are written for the DESKTOP row layout, where
	   `flex: 1 1 260px` / `1 1 520px` are widths — but flex-basis follows the main
	   axis, and this query turns the band into a column, so both became forced
	   HEIGHTS. The meta list holds ~144px of address/phone/hours and was being
	   stretched to 260px, leaving ~116px of empty black under the last line
	   (measured 156-180px from text to card edge). Sizing to content instead. */
	.nbh-discover__copy,
	.nbh-discover__meta { flex: 0 0 auto; }
	.nbh-discover__meta { align-self: flex-start; }
}
@media (max-width: 560px) {
	.nbh-areas__grid { grid-template-columns: 1fr; }
}

/* --- Neighborhood single (SEO landing pages) --------------------------- */
.nbh-single { padding-top: 140px; }
.nbh-single__head { margin: 12px 0 28px; }
.nbh-single__content { max-width: 820px; }
.nbh-single__content h2 { font-size: var(--fs-card-title); margin: 32px 0 12px; }
.nbh-single__content h3 { font-size: var(--fs-20); margin: 24px 0 8px; }
.nbh-single__content p { margin-bottom: 16px; color: var(--c-text-muted); }
.nbh-single__content ul { margin: 0 0 16px 20px; list-style: disc; color: var(--c-text-muted); }
.nbh-single__content a { text-decoration: underline; }
.nbh-single__cta { text-align: center; margin-top: 56px; padding: 48px 24px; background: var(--c-green-light-50); border-radius: var(--r-panel); }

/* ==========================================================================
   Neighborhoods We Serve — internal links to the local-SEO landing pages
   (homepage + deals pages; mirrors the live site's internal linking)
   ========================================================================== */
.nbh-links__list {
	display: flex; flex-wrap: wrap; gap: 10px; margin-top: 40px; padding: 0; list-style: none;
}
.nbh-links__item {
	display: inline-flex; align-items: center; padding: 10px 18px; border-radius: var(--r-pill);
	background: var(--c-green-light-50); border: 1px solid transparent;
	font-size: var(--fs-14); font-weight: var(--fw-medium); color: var(--c-text);
	transition: background .15s ease, border-color .15s ease, transform .15s ease;
}
.nbh-links__item:hover, .nbh-links__item:focus-visible {
	background: var(--c-green-light); border-color: var(--c-green-mid); transform: translateY(-1px);
}
.nbh-links__cta { margin-top: 32px; }
/* "More Kushology Deals" is two buttons and sits directly on .nbh-links. Its
   --section-py-sm bottom plus that section's --section-py top left 200px of empty
   page between two short rows. Let the following section own the whole gap. */
.deals-siblings { padding-bottom: 0; }
/* The h2 and the button row had NO gap between them (measured 0px) — the heading
   sat directly on top of the pills. .h2 carries no bottom margin and the <p>
   wrapper's is reset globally, so neither side supplied one. */
.deals-siblings__links { margin-top: 24px; display: flex; flex-wrap: wrap; gap: 12px; }

@media (max-width: 760px) {
	.nbh-links__list { gap: 8px; margin-top: 28px; }
	.nbh-links__item { padding: 9px 14px; font-size: var(--fs-12); }
}

/* Around-the-City tiles are links to each landmark's official site (parity with
   the live page). The tile is already a card, so it just needs link affordance. */
.tile--link { text-decoration: none; transition: transform .18s ease, box-shadow .18s ease; }
.tile--link:hover { transform: translateY(-4px); box-shadow: 0 18px 40px rgba(0,0,0,.18); }
.tile--link:hover .tile__title { text-decoration: underline; }
.tile--link:focus-visible { outline: 3px solid var(--c-green-mid); outline-offset: 3px; }

/* Product rail injected under the "Shop Cannabis …" heading on neighborhood pages
   (see kushology_neighborhoods_inject_products). */
.nbh-shop { margin: 28px 0 48px; }
.nbh-shop .card-row { gap: var(--gap-md); }
.nbh-shop .product-card { flex: 0 0 240px; width: 240px; }
.nbh-shop__cta { margin-top: 28px; }
@media (max-width: 760px) {
	.nbh-shop .product-card { flex-basis: 62vw; width: 62vw; }
}

/* ==========================================================================
   Footer — mobile single column
   --------------------------------------------------------------------------
   Ordering fix, not a new rule. `@media (max-width: 560px)` already sets the
   footer to one column (~line 948), but a LATER `@media (max-width: 900px)`
   block re-declares `grid-template-columns: 1fr 1fr`. On a phone BOTH queries
   match, and at equal specificity the later declaration wins — so the footer
   stayed two-up and the signup form rendered at half width with the Shop column
   beside it. Re-asserting after both blocks is what actually makes it stick.
   ========================================================================== */
@media (max-width: 640px) {
	.site-footer__top {
		grid-template-columns: 1fr;
		gap: 40px;
	}
	/* Full-width form: the signup is its own row now, so nothing constrains it. */
	.site-footer__signup {
		max-width: none;
		width: 100%;
	}
	/* First/Last name stop sharing a row at this width too. */
	.site-footer__form .gform_fields {
		grid-template-columns: 1fr;
	}
}

/* ==========================================================================
   Product description — readable structure
   Meadow copy arrives as label-on-its-own-line ("Unmatched Potency:") followed
   by prose. kushology_format_product_description() promotes those labels to
   sub-headings; this gives the result real rhythm instead of one text wall.
   ========================================================================== */
.product-single__desc p { margin: 0 0 14px; line-height: var(--lh-body); }
.product-single__desc p:last-child { margin-bottom: 0; }
.product-single__subhead {
	font-size: var(--fs-body);
	font-weight: var(--fw-medium);
	color: var(--c-text);
	margin: 22px 0 6px;
	line-height: 1.35;
}
.product-single__subhead:first-child { margin-top: 0; }

/* ==========================================================================
   Header cart button — same green circle as the search button
   Replaces the plugin's bare 🛒 emoji. Badge is black-on-white per Shawn
   (the plugin's default red read as an error state against the lime header).
   ========================================================================== */
.site-header__cart {
	position: relative;
	width: 48px; height: 48px; flex: 0 0 auto; padding: 0;
	border: none; border-radius: var(--r-pill);
	background: var(--c-green-mid); color: var(--c-black);
	display: grid; place-items: center; cursor: pointer;
	transition: transform .15s ease, background .18s ease;
}
.site-header__cart:hover { transform: translateY(-1px); background: var(--c-green-light); }
.site-header__cart .icon { width: 24px; height: 24px; }
.site-header__cart.is-empty { display: none; }

/* Count badge — black pill, white numerals, notched over the top-right edge. */
.site-header__cart .meadow-cart-count {
	position: absolute; top: -4px; right: -4px;
	display: grid; place-items: center;
	/* A pill, not a fixed circle. It was 20x20 with border-radius:10px, so a
	   two-digit count grew wider than 20px and the fixed radius stopped matching
	   the height — the corners squared off and "14" sat hard against the edges.
	   999px keeps it a true pill at any width, and the extra height/padding gives
	   the numerals room: box-sizing is border-box, so the 2px ring was eating
	   4px of the 20px box. */
	/* width:max-content is the part that actually fixes it. As an absolutely
	   positioned grid box the used width was resolving to the min-width (22px)
	   instead of shrink-to-fitting, so "14" and "100" painted straight out of the
	   disc. min-width keeps it a circle at one digit. */
	width: max-content; min-width: 22px; height: 22px; padding: 0 7px;
	border-radius: 999px;
	background: var(--c-black); color: var(--c-white);
	font-size: 11px; font-weight: var(--fw-medium); line-height: 1;
	font-variant-numeric: tabular-nums;   /* digits stop jittering as the count changes */
	border: 2px solid var(--c-green-light);   /* separates the badge from the circle */
	margin: 0; vertical-align: baseline;
}

@media (max-width: 900px) {
	/* Sits immediately right of the search circle, same 40px treatment. */
	.site-header__cart {
		position: absolute; left: 64px; top: 50%; translate: 0 -50%;
		width: 40px; height: 40px;
	}
	.site-header__cart .icon, .site-header__cart svg { width: 18px; height: 18px; }
	.site-header__cart .meadow-cart-count {
		min-width: 18px; height: 18px; top: -3px; right: -3px; font-size: 10px;
	}
}

/* Drawer row thumbnails — the plugin's markup has none; main.js injects them. */
.kush-cart-thumb {
	width: 44px; height: 44px; object-fit: contain; flex: 0 0 auto;
	border-radius: var(--r-card-sm); background: var(--c-green-light);
	margin-right: 12px; vertical-align: middle; display: inline-block;
}
.meadow-cart-table td:first-child { display: flex; align-items: center; gap: 0; }

/* ==========================================================================
   Shop — sticky filter sidebar (desktop) / full-screen drawer (mobile)
   ========================================================================== */
.shop-layout { display: grid; grid-template-columns: 264px minmax(0, 1fr); gap: 40px; align-items: start; }
.shop-layout__main { min-width: 0; }

/* --- Sidebar ------------------------------------------------------------- */
.shop-filters { position: sticky; top: 104px; max-height: calc(100vh - 128px); display: flex; }
.shop-filters__inner { width: 100%; overflow-y: auto; padding-right: 4px; }
.shop-filters__inner::-webkit-scrollbar { width: 6px; }
.shop-filters__inner::-webkit-scrollbar-thumb { background: var(--c-border); border-radius: 3px; }
.shop-filters__top { display: flex; align-items: center; gap: 12px; padding-bottom: 12px; }
.shop-filters__title { font-size: var(--fs-20); font-weight: var(--fw-medium); margin: 0; }
.shop-filters__clear { margin-left: auto; font-size: var(--fs-12); text-decoration: underline; color: var(--c-text-muted); }
.shop-filters__close, .shop-filters__actions { display: none; }

.shop-facet { border-top: 1px solid var(--c-divider); padding: 14px 0; }
.shop-facet__head {
	display: flex; align-items: center; justify-content: space-between; gap: 8px;
	cursor: pointer; list-style: none; font-weight: var(--fw-medium); font-size: var(--fs-14);
}
.shop-facet__head::-webkit-details-marker { display: none; }
/* +/− marker drawn in CSS so it animates and needs no icon font */
.shop-facet__marker { position: relative; width: 14px; height: 14px; flex: 0 0 auto; }
.shop-facet__marker::before, .shop-facet__marker::after {
	content: ""; position: absolute; left: 50%; top: 50%; background: currentColor;
	translate: -50% -50%; transition: opacity .18s ease, rotate .18s ease;
}
.shop-facet__marker::before { width: 12px; height: 1.5px; }
.shop-facet__marker::after { width: 1.5px; height: 12px; }
.shop-facet[open] .shop-facet__marker::after { opacity: 0; rotate: 90deg; }

.shop-facet__list { display: flex; flex-direction: column; gap: 2px; margin: 10px 0 2px; padding: 0; list-style: none; }
.shop-facet__opt {
	display: flex; align-items: center; gap: 10px; padding: 7px 6px; border-radius: 8px;
	font-size: var(--fs-14); color: var(--c-text); transition: background .15s ease;
}
.shop-facet__opt:hover { background: var(--c-green-light-50); }
.shop-facet__box {
	width: 17px; height: 17px; flex: 0 0 auto; border-radius: 4px;
	border: 1.5px solid var(--c-border-strong); background: var(--c-white);
	display: grid; place-items: center; transition: background .15s ease, border-color .15s ease;
}
.shop-facet__opt.is-on .shop-facet__box { background: var(--c-black); border-color: var(--c-black); }
.shop-facet__opt.is-on .shop-facet__box::after {
	content: ""; width: 9px; height: 5px; border-left: 2px solid #fff; border-bottom: 2px solid #fff;
	rotate: -45deg; translate: 0 -1px;
}
.shop-facet__label { flex: 1; min-width: 0; }
.shop-facet__count { color: var(--c-text-muted); font-size: var(--fs-12); }
.shop-facet__opt.is-on .shop-facet__label { font-weight: var(--fw-medium); }

/* --- Toolbar ------------------------------------------------------------- */
.shop-toolbar { margin-bottom: 24px; }
.shop-toolbar__row { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.shop-toolbar__count { margin: 0; font-size: var(--fs-14); color: var(--c-text-muted); }
.shop-toolbar__count strong { color: var(--c-text); font-weight: var(--fw-medium); }
.shop-toolbar__sort { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.shop-toolbar__sort-label { font-size: var(--fs-14); color: var(--c-text-muted); }
.shop-toolbar__chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.shop-toolbar__filter-btn { display: none; }

@media (max-width: 1024px) {
	.shop-layout { grid-template-columns: 216px minmax(0, 1fr); gap: 28px; }
}

/* --- Mobile: sidebar becomes a full-screen drawer ------------------------ */
@media (max-width: 860px) {
	.shop-layout { grid-template-columns: 1fr; gap: 0; }

	.shop-toolbar__filter-btn {
		display: inline-flex; align-items: center; gap: 8px;
		height: 44px; padding: 0 18px; border-radius: var(--r-pill);
		border: 1px solid var(--c-border); background: var(--c-white);
		font-family: inherit; font-size: var(--fs-14); font-weight: var(--fw-medium); cursor: pointer;
	}
	.shop-toolbar__filter-btn .icon { width: 18px; height: 18px; }
	.shop-toolbar__badge {
		display: grid; place-items: center; min-width: 20px; height: 20px; padding: 0 6px;
		border-radius: 10px; background: var(--c-black); color: #fff; font-size: 11px;
	}
	.shop-toolbar__sort { margin-left: auto; }
	.shop-toolbar__sort-label { display: none; }
	.shop-toolbar__count { order: 3; width: 100%; }

	.shop-filters {
		position: fixed; inset: 0; z-index: 9997; max-height: none; display: block;
		background: var(--c-white);
		transform: translateY(100%); visibility: hidden;
		transition: transform .32s cubic-bezier(.4,0,.2,1), visibility .32s;
	}
	.shop-filters.is-open { transform: translateY(0); visibility: visible; }
	.shop-filters__inner {
		display: flex; flex-direction: column; height: 100%; overflow: hidden;
		padding: 20px 20px 0;
	}
	.shop-filters__top {
		padding: 4px 0 16px; border-bottom: 1px solid var(--c-divider); flex: 0 0 auto;
	}
	.shop-filters__title { font-size: var(--fs-22); }
	.shop-filters__facets { flex: 1 1 auto; overflow-y: auto; -webkit-overflow-scrolling: touch; }
	.shop-filters__close {
		display: grid; place-items: center; width: 40px; height: 40px; padding: 0;
		border: 1px solid var(--c-border); border-radius: var(--r-pill);
		background: var(--c-white); font-size: 22px; line-height: 1; cursor: pointer;
	}
	.shop-filters__actions {
		display: block; flex: 0 0 auto; padding: 16px 0 calc(16px + env(safe-area-inset-bottom));
		border-top: 1px solid var(--c-divider); background: var(--c-white);
	}
	.shop-filters__apply { width: 100%; justify-content: center; }
	.shop-facet__opt { padding: 11px 6px; }   /* larger touch targets */
	body.filters-open { overflow: hidden; }
}

/* ==========================================================================
   Potency range facet (THC / CBD) — two native range inputs sharing one track.
   Hidden until the catalog carries the data (kushology_show_potency()).
   ========================================================================== */
.range { padding: 14px 4px 6px; }
.range__readout { display: block; font-size: var(--fs-14); font-weight: var(--fw-medium); margin-bottom: 14px; }
.range__track { position: relative; height: 22px; }
.range__track::before {
	content: ""; position: absolute; left: 0; right: 0; top: 50%; translate: 0 -50%;
	height: 4px; border-radius: 2px; background: var(--c-border);
}
.range__fill {
	position: absolute; top: 50%; translate: 0 -50%; height: 4px; border-radius: 2px;
	background: var(--c-black);
}
/* Both inputs stack on the track; only their thumbs take pointer events, so each
   handle stays independently grabbable instead of the top input eating all clicks. */
.range__input {
	position: absolute; inset: 0; width: 100%; margin: 0; height: 22px;
	appearance: none; -webkit-appearance: none; background: none; pointer-events: none;
}
.range__input:focus { outline: none; }
.range__input::-webkit-slider-thumb {
	-webkit-appearance: none; pointer-events: auto;
	width: 20px; height: 20px; border-radius: 50%; cursor: grab;
	background: var(--c-black); border: 3px solid var(--c-white);
	box-shadow: 0 1px 4px rgba(0,0,0,.35);
}
.range__input::-moz-range-thumb {
	pointer-events: auto; width: 20px; height: 20px; border-radius: 50%; cursor: grab;
	background: var(--c-black); border: 3px solid var(--c-white); box-shadow: 0 1px 4px rgba(0,0,0,.35);
}
.range__input:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--c-green-mid); outline-offset: 2px; }
.range__noscript { display: flex; gap: 8px; margin-top: 12px; }
.range__noscript input { width: 74px; height: 38px; padding: 0 10px; border: 1px solid var(--c-border); border-radius: var(--r-card-sm); font-family: inherit; }

/* ==========================================================================
   Product info: card spec row + detail spec panel
   Strain / size / potency are what shoppers compare on, so they get their own
   row rather than being buried in the meta line.
   ========================================================================== */
.product-card__body { display: flex; flex-direction: column; gap: 6px; }
.product-card__brand {
	font-size: var(--fs-12); color: var(--c-text-muted);
	text-transform: uppercase; letter-spacing: .06em; font-weight: var(--fw-medium);
}
.product-card__specs {
	display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 0; padding: 0; list-style: none;
}
.product-card__specs li {
	font-size: var(--fs-12); line-height: 1;
	padding: 5px 8px; border-radius: 6px;
	background: rgba(255,255,255,.55); color: var(--c-text-muted);
}
.product-card__specs strong { color: var(--c-text); font-weight: var(--fw-medium); }
/* Strain reads as a badge, colour-coded so the three types are scannable. */
.product-card__strain { font-weight: var(--fw-medium); color: var(--c-text) !important; }
.product-card__strain--indica { background: #e6ddf5; }
.product-card__strain--sativa { background: #fdeecb; }
.product-card__strain--hybrid { background: #d6ecd4; }
.product-card__price { margin-top: 4px; font-weight: var(--fw-medium); font-size: var(--fs-body); }

.product-specs {
	display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 10px;
	margin: 22px 0; padding: 0; list-style: none;
}
.product-specs__item {
	display: flex; flex-direction: column; gap: 4px;
	padding: 12px 14px; border-radius: var(--r-card); background: var(--c-green-light-50);
}
.product-specs__label { font-size: var(--fs-12); color: var(--c-text-muted); text-transform: uppercase; letter-spacing: .06em; }
.product-specs__value { font-size: var(--fs-body); font-weight: var(--fw-medium); }
.product-specs__strain--indica, .product-specs__strain--sativa, .product-specs__strain--hybrid { text-transform: capitalize; }

/* ==========================================================================
   Product card v2 — reference layout (strain badge · potency pill · footer rule
   with price left / black add button right). Green ground stays ours.
   Overrides the earlier card rules further up this file.
   ========================================================================== */
.product-card { padding: 14px 14px 12px; gap: 0; }

/* Media + strain badge overlay */
.product-card__media { position: relative; margin-bottom: 14px; }
.product-card__strain {
	position: absolute; top: 0; left: 0; z-index: 2;
	padding: 5px 11px; border-radius: var(--r-pill);
	font-size: var(--fs-12); font-weight: var(--fw-medium); line-height: 1;
	color: var(--c-text); background: rgba(255,255,255,.82);
	backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}
.product-card__strain--indica { background: rgba(232,222,248,.92); }
.product-card__strain--sativa { background: rgba(253,238,203,.94); }
.product-card__strain--hybrid { background: rgba(214,236,212,.94); }

/* Body */
.product-card__body { display: flex; flex-direction: column; gap: 5px; }
.product-card__potency {
	align-self: flex-start; padding: 6px 12px; margin-bottom: 3px;
	border: 1px solid rgba(0,0,0,.28); border-radius: var(--r-pill);
	font-size: var(--fs-12); font-weight: var(--fw-medium); color: var(--c-text); line-height: 1;
}
.product-card__brand {
	font-size: var(--fs-12); color: var(--c-text-muted);
	font-weight: var(--fw-medium); letter-spacing: .02em;
}
.product-card__name {
	font-weight: var(--fw-medium); font-size: var(--fs-body); line-height: 1.25; color: var(--c-text);
}
.product-card__name:hover { text-decoration: underline; }
.product-card__amt { font-size: var(--fs-12); color: var(--c-text-muted); font-weight: var(--fw-medium); }

/* Footer: rule, price left, add button right */
.product-card__foot {
	display: flex; align-items: center; justify-content: space-between; gap: 10px;
	margin-top: auto; padding-top: 12px;
	border-top: 1px solid rgba(0,0,0,.14);
}
.product-card__price { font-size: var(--fs-20); font-weight: var(--fw-medium); margin: 0; }
.product-card__price .price del { font-size: var(--fs-14); opacity: .5; margin-right: 5px; }
.product-card__price .price ins { text-decoration: none; }
.product-card__add {
	position: static;             /* was absolutely placed over the artwork */
	width: 40px; height: 40px; flex: 0 0 auto; padding: 0;
	border: none; border-radius: 50%;
	background: var(--c-black); color: var(--c-white);
	display: grid; place-items: center; cursor: pointer;
	font-size: 22px; line-height: 1;
	transition: transform .15s ease, opacity .15s ease;
}
.product-card__add:hover {
	/* Glow, not a colour change — the disc stays black (Shawn). */
	transform: scale(1.06);
	box-shadow: 0 0 0 6px rgba(0,0,0,.10), 0 4px 14px rgba(0,0,0,.28);
}
.product-card__add.is-added { background: var(--c-black); }

@media (max-width: 560px) {
	.product-card { padding: 12px 12px 10px; }
	.product-card__price { font-size: var(--fs-body); }
	.product-card__add { width: 36px; height: 36px; font-size: 20px; }
}

/* --- Filter sidebar: hide the scrollbar chrome, keep the scrolling ---------
   The visible track cut through the panel next to the checkbox counts. Scrolling
   still works by wheel, trackpad, touch and keyboard — only the indicator is
   hidden (scrollbar-gutter avoids a width jump when it would have appeared). */
.shop-filters__inner {
	scrollbar-width: none;              /* Firefox */
	-ms-overflow-style: none;           /* legacy Edge */
	padding-right: 0;
}
.shop-filters__inner::-webkit-scrollbar { width: 0; height: 0; display: none; }
@media (max-width: 860px) {
	.shop-filters__facets { scrollbar-width: none; -ms-overflow-style: none; }
	.shop-filters__facets::-webkit-scrollbar { width: 0; height: 0; display: none; }
}

/* --- Card footer rule + quantity control ---------------------------------
   The rule sat tight under the title and read too heavy; more breathing room
   above it and a fainter line. ------------------------------------------- */
.product-card__foot {
	margin-top: 14px;
	padding-top: 14px;
	border-top: 1px solid rgba(0,0,0,.09);
}

/* The Meadow cart JS rewrites the button's textContent to "Adding…"/"Added" on
   click, which blew the round button open. Keep the disc fixed and clip anything
   it injects; our own label is painted back from cart state (see main.js). */
.product-card__add {
	overflow: hidden;
	white-space: nowrap;
	font-size: 0;                       /* hides plugin-injected text */
	line-height: 1;
}
.product-card__add > span,
.product-card__add .product-card__qty-label {
	font-size: 22px;
	line-height: 1;
	display: block;
}
/* In-cart: the disc shows the quantity instead of "+" */
.product-card__add.is-in-cart > span { font-size: var(--fs-body); font-weight: var(--fw-medium); }

/* Inline stepper — replaces the disc when the quantity is tapped */
.product-card__stepper {
	display: none; align-items: center; gap: 2px;
	background: var(--c-black); border-radius: var(--r-pill); padding: 3px;
}
.product-card__stepper.is-open { display: inline-flex; }
.product-card__stepper button {
	width: 30px; height: 30px; padding: 0; border: none; border-radius: 50%;
	background: transparent; color: var(--c-white); cursor: pointer;
	font-size: 17px; line-height: 1; display: grid; place-items: center;
}
.product-card__stepper button:hover { background: rgba(255,255,255,.16); }
.product-card__stepper output {
	min-width: 22px; text-align: center; color: var(--c-white);
	font-size: var(--fs-14); font-weight: var(--fw-medium);
}
.product-card__foot.is-editing .product-card__add { display: none; }
/* The homepage hero carousel runs the same stepper in its own smaller foot. */
.pcard-mini__foot.is-editing .pcard-mini__add { display: none; }

/* Coverage note inside the potency facet — the data only spans part of the
   catalog until the Meadow sync imports cannabinoids. */
.range__note { margin: 0 0 10px; font-size: var(--fs-12); color: var(--c-text-muted); }

/* --- Compounds facet: THC + CBD sliders grouped under one heading ---------
   Each row carries its own inline label + readout, so the two are legible
   without a separate accordion each. -------------------------------------- */
.shop-facet__compounds { padding-top: 10px; }
.shop-facet__compounds .range { padding: 4px 4px 14px; }
.shop-facet__compounds .range + .range {
	margin-top: 4px; padding-top: 14px; border-top: 1px solid rgba(0,0,0,.07);
}
.range__head {
	display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
	margin-bottom: 12px;
}
.range__label { font-size: var(--fs-14); font-weight: var(--fw-medium); }
.range__readout { font-size: var(--fs-14); color: var(--c-text-muted); font-weight: var(--fw-medium); margin: 0; }
.shop-facet__compounds .range__note { margin: 0 4px 12px; }

/* --- Card rhythm: identical footer position across a row ------------------
   The v2 rules set `margin-top: 14px` on the footer, which dropped the
   `margin-top:auto` that pinned it to the bottom — so a two-line title pushed
   its price/button lower than its neighbours. Restore the push, and give the
   title a fixed two-line box (clamped, so a third line truncates) so every card
   in a row lines up whether the name wraps or not. ----------------------- */
.product-card { display: flex; flex-direction: column; height: 100%; }
.product-card__body { flex: 1 1 auto; }

.product-card__name {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	/* Exactly two lines tall even when the title is one, so the rule and the
	   button sit at the same height across the row. */
	min-height: calc(2 * 1.25 * var(--fs-body));
}

.product-card__foot {
	margin-top: auto;   /* was 14px — this is what pins the row to the bottom */
	padding-top: 14px;
}

/* ==========================================================================
   Cart drawer v2 — wider, calmer, on-brand
   ========================================================================== */
.meadow-cart-sidebar {
	width: min(468px, 94vw) !important;              /* was 420px */
	box-shadow: -24px 0 70px rgba(0,0,0,.22);
}
.meadow-cart-header {
	padding: 26px 28px 20px;
	border-bottom: 1px solid var(--c-divider);
}
.meadow-cart-header strong { font-size: var(--fs-22); font-weight: var(--fw-medium); letter-spacing: -.01em; }
.meadow-cart-content { padding: 8px 28px 20px; }
.meadow-cart-footer { padding: 22px 28px calc(22px + env(safe-area-inset-bottom)); }

/* Rows read as line items rather than a data table */
.meadow-cart-table tr { border-bottom: 1px solid var(--c-divider); }
.meadow-cart-table tr:last-child { border-bottom: none; }
.meadow-cart-table td { padding: 16px 4px; }
.meadow-cart-table td:first-child { gap: 12px; font-weight: var(--fw-medium); line-height: 1.3; }
.kush-cart-thumb { width: 52px; height: 52px; border-radius: var(--r-card); }

/* −/+ stepper wrapping the plugin's number input */
.kush-qty {
	display: inline-flex; align-items: center; gap: 2px;
	border: 1px solid var(--c-border); border-radius: var(--r-pill);
	padding: 3px; background: var(--c-white);
}
.kush-qty__btn {
	width: 28px; height: 28px; padding: 0; border: none; border-radius: 50%;
	background: transparent; color: var(--c-text); cursor: pointer;
	font-size: 16px; line-height: 1; display: grid; place-items: center;
	transition: background .15s ease;
}
.kush-qty__btn:hover { background: var(--c-green-light); }
.kush-qty .meadow-cart-qty {
	width: 34px; height: 28px; padding: 0; margin: 0;
	border: none; background: transparent; text-align: center;
	font-family: inherit; font-size: var(--fs-14); font-weight: var(--fw-medium);
	-moz-appearance: textfield;
}
.kush-qty .meadow-cart-qty::-webkit-outer-spin-button,
.kush-qty .meadow-cart-qty::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* Summary + actions */
.meadow-cart-summary { gap: 10px; margin-bottom: 18px; }
.meadow-cart-summary > div { color: var(--c-text-muted); }
.meadow-cart-total { font-size: var(--fs-20); padding-top: 12px; }
.meadow-cart-total span:last-child { font-weight: var(--fw-medium); }
.meadow-cart-actions { gap: 12px; }
.meadow-checkout-btn { padding: 17px; font-size: var(--fs-body); }
#meadow-reset-cart { padding: 17px 20px; color: var(--c-text-muted); }
#meadow-reset-cart:hover { background: var(--c-green-light-50); }

@media (max-width: 560px) {
	.meadow-cart-sidebar { width: 100vw !important; }
	.meadow-cart-header, .meadow-cart-content, .meadow-cart-footer { padding-left: 20px; padding-right: 20px; }
}

/* Breathing room between the title and the footer rule — the two-line title box
   ended flush against the divider. */
.product-card__body { padding-bottom: 10px; }
.product-card__name { margin-bottom: 2px; }

/* ==========================================================================
   Cart drawer rows — escape the plugin's <table>
   --------------------------------------------------------------------------
   The plugin emits name / qty / price / remove as four <td>s sized by the
   browser for a bare number input, so the −/+ stepper (128px) overflowed its
   74px cell and collided with the price, and long titles were clipped. Dropping
   table display and laying each row out as a grid gives the reference layout:
   thumbnail + wrapping title on the left, price / quantity / remove stacked on
   the right, with rows tall enough to read.
   ========================================================================== */
.meadow-cart-table,
.meadow-cart-table tbody { display: block; width: 100%; }

/* The plugin's header row (Product / Quantity / Price) is redundant once rows
   are self-describing. */
.meadow-cart-table tr:first-child:not([data-product-id]) { display: none; }

.meadow-cart-table tr[data-product-id] {
	display: grid;
	grid-template-columns: 1fr auto;
	column-gap: 16px;
	row-gap: 8px;
	align-items: start;
	padding: 18px 0;
	border-bottom: 1px solid var(--c-divider);
}
.meadow-cart-table tr[data-product-id]:last-child { border-bottom: none; }
.meadow-cart-table td { display: block; padding: 0; border: none; }

/* 1) thumbnail + title — wraps fully instead of truncating */
.meadow-cart-table td:nth-child(1) {
	grid-column: 1; grid-row: 1 / span 3;
	display: flex; align-items: flex-start; gap: 14px;
	font-size: var(--fs-14); font-weight: var(--fw-medium);
	line-height: 1.35; white-space: normal; overflow: visible; text-overflow: clip;
}
.kush-cart-thumb { width: 58px; height: 58px; flex: 0 0 auto; margin: 0; }

/* 2) price sits top-right, like the reference */
.meadow-cart-table td:nth-child(3) {
	grid-column: 2; grid-row: 1;
	text-align: right; font-weight: var(--fw-medium); font-size: var(--fs-body);
	white-space: nowrap;
}
/* 3) quantity stepper below it */
.meadow-cart-table td:nth-child(2) { grid-column: 2; grid-row: 2; justify-self: end; }
/* 4) remove, quietly, underneath */
.meadow-cart-table td:nth-child(4) { grid-column: 2; grid-row: 3; justify-self: end; }
.meadow-remove-product {
	width: auto; height: auto; padding: 0; border: none; background: none;
	font-size: var(--fs-12); color: var(--c-text-muted); text-decoration: underline;
}
.meadow-remove-product::before { content: "Remove"; position: static; display: inline; font-size: inherit; }
.meadow-remove-product:hover { background: none; color: var(--c-text); }

/* Stepper now has room to breathe */
.kush-qty { padding: 3px; }
.kush-qty .meadow-cart-qty { width: 30px; }

/* The right-hand column was sized by `justify-self: end`, which shrinks a grid
   item to min-content — so the 128px stepper sat in a 26px cell and spilled over
   the price. Give the column a floor that fits the stepper and right-align the
   contents inside each cell instead of shrinking the cells themselves. */
.meadow-cart-table tr[data-product-id] { grid-template-columns: 1fr minmax(132px, auto); }
.meadow-cart-table td:nth-child(2),
.meadow-cart-table td:nth-child(3),
.meadow-cart-table td:nth-child(4) {
	justify-self: stretch;
	display: flex;
	justify-content: flex-end;
	align-items: center;
}
.kush-qty { flex: 0 0 auto; }

/* Explicit widths: the cells kept resolving to min-content (26px) even with the
   track at 132px and justify-self: stretch — table cells carry sizing baggage
   that survives `display: block`. Stating the width outright ends the argument. */
.meadow-cart-table td:nth-child(2),
.meadow-cart-table td:nth-child(3),
.meadow-cart-table td:nth-child(4) {
	width: 132px;
	min-width: 132px;
	max-width: 132px;
	box-sizing: border-box;
}
.meadow-cart-table td:nth-child(1) { min-width: 0; }   /* lets the title wrap instead of forcing the row wide */

/* --- Cart drawer: make the item list actually scroll ----------------------
   The list is a flex child with overflow-y: auto, but a flex item's default
   `min-height: auto` won't let it shrink below its content — so instead of
   scrolling it grew past the drawer and the last item hid behind the footer.
   min-height: 0 is what lets the overflow engage. The header and footer stay
   pinned so only the items move. */
.meadow-cart-sidebar { overflow: hidden; }
.meadow-cart-header,
.meadow-cart-footer { flex: 0 0 auto; }
.meadow-cart-content {
	flex: 1 1 auto;
	min-height: 0;              /* the fix */
	overflow-y: auto;
	overscroll-behavior: contain;   /* stop the page behind scrolling at the ends */
	-webkit-overflow-scrolling: touch;
	/* Hide the scrollbar chrome, matching the filter sidebar. */
	scrollbar-width: none;
	-ms-overflow-style: none;
}
.meadow-cart-content::-webkit-scrollbar { width: 0; height: 0; display: none; }

/* The plugin positions the cart footer ABSOLUTELY, so it sits outside the flex
   column: the item list was handed the drawer's entire remaining height and the
   footer simply painted on top of it, hiding the last rows with nothing to
   scroll. Returning the footer to the normal flow lets the column allocate real
   space to it, which is what finally lets the list shrink and scroll. */
.meadow-cart-footer {
	position: static !important;
	inset: auto !important;
	width: auto !important;
}

/* The description's last paragraph zeroes its bottom margin, and the attribute
   list's first row draws its own border-top — so the closing sentence sat
   directly on that rule. Pad the description block instead of re-adding margin
   to the paragraph, so the gap holds whether the copy ends in a paragraph, a
   sub-heading or a list. */

/* Share button — sits on the title row, quiet until hovered. */
.product-single__titlerow { display: flex; align-items: flex-start; gap: 16px; }
.product-single__titlerow .product-single__title { flex: 1 1 auto; }
@media (max-width: 560px) {
}

/* Drawer title icon (replaces the plugin's 🛒 emoji) */
.meadow-cart-header strong { display: inline-flex; align-items: center; gap: 10px; }
.meadow-cart-header__icon { width: 22px; height: 22px; flex: 0 0 auto; color: var(--c-text); }

/* Contact submit was landing at 38px — Gravity Forms' own button height won,
   because this rule set `height` without !important (the footer form's
   equivalent has it, which is why that one sits correctly). Match the 56px of
   the fields above it so the form reads as one stack. */
.contact__form .gform_wrapper .gform_footer input[type=submit],
.contact__form .gform_wrapper .gform_button {
	height: var(--btn-h) !important;
	font-size: var(--fs-body) !important;
}

/* ==========================================================================
   Back to top — shop screens only
   Bottom-RIGHT: the accessibility widget occupies bottom-left. z-index sits
   above page content but below the cart drawer (9999) and its backdrop (9998),
   so an open cart is never overlapped.
   ========================================================================== */
.to-top {
	position: fixed; z-index: 60;
	right: clamp(16px, 3vw, 32px);
	bottom: calc(clamp(16px, 3vw, 32px) + env(safe-area-inset-bottom));
	width: 48px; height: 48px; padding: 0;
	border: none; border-radius: 50%;
	background: var(--c-green-mid); color: var(--c-black);
	display: grid; place-items: center; cursor: pointer;
	box-shadow: 0 6px 20px rgba(0,0,0,.16);
	opacity: 0; transform: translateY(10px);
	transition: opacity .2s ease, transform .2s ease, background .15s ease;
}
.to-top.is-visible { opacity: 1; transform: none; }
.to-top:hover { background: var(--c-green-light); }
.to-top:focus-visible { outline: 2px solid var(--c-black); outline-offset: 3px; }
.to-top .icon { width: 22px; height: 22px; }
/* An open cart drawer covers the right edge — get out of its way. */
body.cart-open .to-top { opacity: 0; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
	.to-top { transition: opacity .2s ease; transform: none; }
}
@media (max-width: 560px) { .to-top { width: 44px; height: 44px; } }

/* ==========================================================================
   Brands index (/brands/) — restores the retired embed's brands route
   ========================================================================== */
.brand-jump { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 32px; }
.brand-jump__item {
	display: grid; place-items: center; min-width: 34px; height: 34px; padding: 0 8px;
	border-radius: var(--r-pill); border: 1px solid var(--c-border);
	font-size: var(--fs-14); font-weight: var(--fw-medium);
	transition: background .15s ease, border-color .15s ease;
}
.brand-jump__item:hover { background: var(--c-green-light); border-color: var(--c-green-mid); }
.brand-group { margin-bottom: 36px; scroll-margin-top: 110px; }
.brand-group__letter {
	font-size: var(--fs-20); margin: 0 0 14px; padding-bottom: 8px;
	border-bottom: 1px solid var(--c-divider);
}
.brand-list {
	list-style: none; margin: 0; padding: 0;
	display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px;
}
.brand-card {
	display: flex; flex-direction: column; gap: 3px; height: 100%;
	padding: 14px 16px; border-radius: var(--r-card);
	background: var(--c-green-light-50); border: 1px solid transparent;
	transition: background .15s ease, border-color .15s ease, transform .15s ease;
}
.brand-card:hover { background: var(--c-green-light); border-color: var(--c-green-mid); transform: translateY(-2px); }
.brand-card__name { font-weight: var(--fw-medium); line-height: 1.25; }
.brand-card__count { font-size: var(--fs-12); color: var(--c-text-muted); }
@media (max-width: 560px) { .brand-list { grid-template-columns: 1fr 1fr; } }

/* --- Spec panel now sits ABOVE the description ---------------------------
   It used to follow the description, which put the Strain badge below a parsed
   "Phenotype: Sativa" row saying the same thing. The badge leads now (the
   duplicate row is suppressed in kushology_format_product_description), so the
   margins move with it: breathing room under the panel, and the description's
   own top border provides the separation. */
.product-specs { margin: 4px 0 26px; }

/* Strain badge in the product-detail badge row — matches the Type / In-stock
   pills it now sits beside (it used to live alone in the spec panel below). */
.product-single__strain {
	display: inline-flex; align-items: center;
	padding: 8px 16px; border-radius: var(--r-pill);
	background: var(--c-green-light); color: var(--c-text);
	font-size: var(--fs-14); font-weight: var(--fw-medium); line-height: 1;
}

/* ==========================================================================
   Share — icon only, glass, pinned to the image's top-right
   Anchored to the GRID rather than the info column so "top" is the image's top
   edge and "right" is the same page inset the image has on the left.
   ========================================================================== */
.product-single__grid { position: relative; }
/* Icon only at every size — the label stays for screen readers. */

/* --- Gap between the description's spec rows and the Category/Brand list ---
   The description carried a 26px bottom pad AND the attrs list opens with its
   own rule, so the two stacked into a visible hole. */

/* --- Footer signup fields: readable frosted glass -------------------------
   They were a flat 10% white over a photograph, so the fields barely separated
   from the background and the placeholders were hard to read. Blur the backdrop
   and lift both the fill and the placeholder contrast. */
.site-footer__form .gform_wrapper input:not([type=submit]),
.site-footer__form .gform_wrapper .ginput_container input {
	background: rgba(255, 255, 255, .16) !important;
	-webkit-backdrop-filter: blur(14px) saturate(160%);
	backdrop-filter: blur(14px) saturate(160%);
	border: 1px solid rgba(255, 255, 255, .28) !important;
	color: var(--c-text-on-dark) !important;
	box-shadow: inset 0 1px 0 rgba(255,255,255,.10);
}
.site-footer__form .gform_wrapper input::placeholder { color: rgba(255,255,255,.78) !important; }
.site-footer__form .gform_wrapper input:focus {
	background: rgba(255, 255, 255, .24) !important;
	border-color: rgba(255, 255, 255, .55) !important;
	outline: none;
}

/* --- Strain badges: one neutral gray everywhere ---------------------------
   They were pastel-coded per type (indica purple / sativa amber / hybrid green)
   on the cards and brand-green on the detail page, so the same label read three
   ways in the grid and a fourth on the product. One gray across both surfaces —
   the strain is stated in words, so colour wasn't carrying the meaning.
   NB: this drops the at-a-glance colour scan; say the word to bring it back. */
.product-card__strain,
.product-card__strain--indica,
.product-card__strain--sativa,
.product-card__strain--hybrid {
	background: rgba(238, 238, 238, .94) !important;
	color: var(--c-text) !important;
}
.product-single__strain {
	background: #eee;
	color: var(--c-text);
}

/* --- Hero carousel cards: shop-card hierarchy, still minimal --------------
   Brand was inline with price on one muted line, which buried both. Same order
   as the shop card now — brand eyebrow, name, price — plus the strain badge, and
   nothing else (no size, stock or footer row) so the cards stay light. */
.pcard-mini__media { position: relative; }
.pcard-mini .product-card__strain { top: 8px; left: 8px; font-size: 11px; padding: 4px 9px; }
.pcard-mini__brand {
	display: block; margin-bottom: 2px;
	font-size: var(--fs-12); font-weight: var(--fw-medium);
	letter-spacing: .06em; text-transform: uppercase; color: var(--c-text-muted);
}
.pcard-mini__price {
	display: block; margin-top: 6px;
	font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--c-text);
}
.pcard-mini__price .price del { opacity: .5; margin-right: 5px; font-weight: var(--fw-regular); }
.pcard-mini__price .price ins { text-decoration: none; }

/* --- Hero cards: the shop card's anatomy, compacted -----------------------
   Divider + price-left / add-right foot, matching the grid. The old layout put
   a small pale + over the image and the price in a muted meta line, so the two
   surfaces didn't read as the same product card. Sizes stay smaller than the
   shop's since these sit in a carousel. */
.pcard-mini { display: flex; flex-direction: column; }
.pcard-mini__body { flex: 1 1 auto; }
.pcard-mini__foot {
	display: flex; align-items: center; justify-content: space-between; gap: 10px;
	margin-top: 12px; padding-top: 12px;
	border-top: 1px solid rgba(0,0,0,.10);
}
.pcard-mini__price { margin: 0; font-size: var(--fs-20); font-weight: var(--fw-medium); line-height: 1; }
.pcard-mini__add {
	position: static; flex: 0 0 auto;
	width: 38px; height: 38px; padding: 0;
	border: none; border-radius: 50%;
	background: var(--c-black); color: #fff;
	display: grid; place-items: center; cursor: pointer;
	font-size: 0; line-height: 0;
	transition: transform .15s ease, background .15s ease;
}
.pcard-mini__add > span { font-size: 22px; line-height: 1; font-weight: var(--fw-regular); }
.pcard-mini__add:hover { transform: scale(1.08); }
.pcard-mini__add.is-in-cart { background: var(--c-green-mid); color: var(--c-black); }
.pcard-mini__add.is-in-cart > span { font-size: var(--fs-14); font-weight: var(--fw-medium); }

/* ==========================================================================
   Share menu — bare icon trigger + dropdown
   The disc version competed with the Add to Cart button for attention, and the
   checkmark sat visible because the swap was never gated. Now the trigger is
   just the glyph, and confirmation happens inside the menu on the Copy row.
   ========================================================================== */
.share { position: absolute; top: 0; right: 0; z-index: 3; }
.share__trigger {
	display: grid; place-items: center;
	width: 34px; height: 34px; padding: 0;
	background: none; border: none; cursor: pointer;
	color: var(--c-text-muted);
	border-radius: 50%;
	transition: color .15s ease, background .15s ease;
}
.share__trigger:hover { color: var(--c-text); background: rgba(0,0,0,.05); }
.share__trigger:focus-visible { outline: 2px solid var(--c-green-mid); outline-offset: 2px; }
.share__trigger .icon { width: 18px; height: 18px; }
.share.is-open .share__trigger { color: var(--c-text); background: rgba(0,0,0,.06); }

.share__menu {
	position: absolute; top: calc(100% + 8px); right: 0; z-index: 20;
	min-width: 168px; padding: 6px;
	display: flex; flex-direction: column;
	border-radius: 14px;
	background: rgba(255,255,255,.86);
	-webkit-backdrop-filter: blur(18px) saturate(180%);
	backdrop-filter: blur(18px) saturate(180%);
	border: 1px solid rgba(0,0,0,.07);
	box-shadow: 0 12px 34px rgba(0,0,0,.14);
}
.share__item {
	display: flex; align-items: center; justify-content: space-between; gap: 10px;
	width: 100%; padding: 9px 12px; border: none; border-radius: 9px;
	background: none; cursor: pointer; text-align: left;
	font-family: inherit; font-size: var(--fs-14); font-weight: var(--fw-medium);
	color: var(--c-text); text-decoration: none;
	transition: background .12s ease;
}
.share__item:hover { background: var(--c-green-light-50); }
/* The checkmark belongs to the Copy row and only appears once it has copied —
   it used to render unconditionally next to the trigger. */
.share__item .icon { width: 15px; height: 15px; opacity: 0; transition: opacity .15s ease; }
.share__item.is-done .icon { opacity: 1; }
.share__item.is-done { color: #4b6b16; }

/* ==========================================================================
   Potency meter — THC / CBD with the ratio surfaced
   ========================================================================== */
.potency {
	margin: 4px 0 26px; padding: 18px 20px;
	border-radius: var(--r-card);
	background: linear-gradient(180deg, rgba(216,244,160,.42), rgba(216,244,160,.18));
	border: 1px solid rgba(0,0,0,.06);
}
.potency__head {
	display: flex; align-items: center; justify-content: space-between; gap: 12px;
	margin-bottom: 14px;
}
.potency__title {
	margin: 0; font-size: var(--fs-12); font-weight: var(--fw-medium);
	letter-spacing: .1em; text-transform: uppercase; color: var(--c-text-muted);
}
.potency__ratio {
	display: inline-flex; align-items: baseline; gap: 6px;
	padding: 5px 12px; border-radius: var(--r-pill);
	background: rgba(255,255,255,.72);
	-webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
	border: 1px solid rgba(0,0,0,.05);
}
.potency__ratio-val { font-size: var(--fs-14); font-weight: var(--fw-medium); letter-spacing: -.01em; }
.potency__ratio-key { font-size: 10px; letter-spacing: .08em; color: var(--c-text-muted); }
.potency__row { display: grid; grid-template-columns: 38px 1fr auto; align-items: center; gap: 12px; }
.potency__row + .potency__row { margin-top: 10px; }
.potency__label { font-size: var(--fs-12); font-weight: var(--fw-medium); color: var(--c-text-muted); letter-spacing: .04em; }
.potency__track {
	position: relative; height: 8px; border-radius: 99px;
	background: rgba(0,0,0,.08); overflow: hidden;
}
.potency__fill {
	position: absolute; inset: 0 auto 0 0; width: var(--fill, 0%);
	border-radius: 99px;
	background: linear-gradient(90deg, var(--c-green-mid), #8fbf2e);
	transform-origin: left center;
}
/* CBD reads as the quieter of the two. */
.potency__row--cbd .potency__fill { background: linear-gradient(90deg, #cfe3a6, #a9c977); }
.potency__value { font-size: var(--fs-body); font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; }
/* Grow on first paint; skipped entirely under reduced motion. */
@media (prefers-reduced-motion: no-preference) {
	.potency__fill { animation: potency-grow .9s cubic-bezier(.2,.7,.2,1) both; }
	@keyframes potency-grow { from { width: 0; } to { width: var(--fill, 0%); } }
}

/* The description's spec rows and the Category/Brand list are the same kind of
   list, so they read as one run — the 24px gap between them left a hole. Each
   row already carries its own top rule, which is all the separation needed. */

/* --- Product card media: fixed box so one tall image can't stretch the card --
   A later .product-card__media rule dropped the aspect-ratio the earlier one
   set, leaving the box free to grow — a portrait preroll shot made its card
   noticeably taller than its neighbours in the same row. Restated here (last
   wins) with the image capped inside it. */
.product-card__media {
	aspect-ratio: 1 / 1;
	display: grid; place-items: center;
	overflow: hidden;
}
.product-card__media img {
	max-width: 82%; max-height: 82%;
	width: auto; height: auto;
	object-fit: contain;
}

/* --- Ghost button: proper frosted glass ----------------------------------
   It was a flat 20% white with no blur, so over a photograph it read as a grey
   wash rather than glass. */
.btn--ghost {
	background: rgba(255, 255, 255, .18);
	-webkit-backdrop-filter: blur(20px) saturate(180%);
	backdrop-filter: blur(20px) saturate(180%);
	border: 1px solid rgba(255, 255, 255, .38);
	box-shadow: inset 0 1px 0 rgba(255,255,255,.22), 0 6px 20px rgba(0,0,0,.14);
	color: var(--c-white);
}
.btn--ghost:hover {
	background: rgba(255, 255, 255, .3);
	border-color: rgba(255, 255, 255, .55);
}

/* --- One button height across the site -----------------------------------
   .btn derives its height from padding while Gravity Forms submits were given
   fixed heights, so the three drifted apart (56 / 38 / 54). Both now key off
   --btn-h, so changing it moves everything together. */
.btn { min-height: var(--btn-h); }
.panel .gform_wrapper .gform_footer input[type=submit],
.panel .gform_wrapper .gform_button,
.contact-form .gform_wrapper .gform_footer input[type=submit],
.contact-form .gform_wrapper .gform_button,
.gform_wrapper .gform_footer input[type=submit],
.gform_wrapper .gform_button {
	height: var(--btn-h) !important;
	min-height: var(--btn-h) !important;
}
/* The dark footer signup keeps its own compact scale — it sits in a tighter
   column than the page forms. */
.site-footer__form .gform_wrapper .gform_footer input[type=submit],
.site-footer__form .gform_wrapper .gform_button {
	height: 48px !important; min-height: 48px !important;
}

/* --- Homepage body copy at 16px -------------------------------------------
   Section ledes, card and band copy were 14px, which read small against the
   display type. Bumped on the homepage only, and only for READING copy.
   Deliberately NOT bumped:
     - form controls (field height and placeholder sizing would shift)
     - .legal / consent fine print, which stays small on purpose
     - chips, counts, badges and other labels
   This list is the single place the homepage type scale is adjusted — add to it
   rather than appending a new rule further down the file. */
.home .section-head__body,
.home .nbh-links .section-head__body,
.home .tile__body,
.home .faq__a,
/* .panel__body and .deals__note are 16px globally now, so only the selectors
   without a global rule stay scoped here. */
.home .reviews__lede,
.home .band__body,
.home .featured .text-muted,
.home .recommend .text-muted { font-size: var(--fs-body); }
.home .pcard-mini__brand { font-size: var(--fs-14); }
/* Fine print stays fine print — it was swept up in the bump above. */
.home .legal,
.home .site-footer__terms,
.home .panel .legal { font-size: var(--fs-14); }

/* --- Homepage carousel cards: tighter ------------------------------------
   Same anatomy, less air — the image box was square and the padding generous,
   so the strip ate a lot of vertical space beside the hero. */
.pcard-mini { padding: 14px; }
.pcard-mini__media { aspect-ratio: 4 / 3; margin-bottom: 10px; }
.pcard-mini__media img { max-width: 78%; max-height: 78%; }
.pcard-mini__brand { font-size: var(--fs-12); margin-bottom: 1px; }
.pcard-mini__name { font-size: var(--fs-14); line-height: 1.28; }
.pcard-mini__foot { margin-top: 10px; padding-top: 10px; }
.pcard-mini__price { font-size: var(--fs-body); }
.pcard-mini__add { width: 34px; height: 34px; }
.pcard-mini__add > span { font-size: 19px; }

/* --- Home carousel: title on a single line at every width -----------------
   The clamp was scoped to @media (max-width: 900px), so on desktop titles kept
   `white-space: normal` and a long name ("Z Type-S 2.5g Preroll 5 Pack") wrapped
   to a second line — the text block grew and the row lost its rhythm. One line
   everywhere, ellipsised. The anchor still carries the full title in the DOM, so
   screen readers and crawlers read the whole name; the clamp is visual only. */
.pcard-mini__name {
	display: block;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* `[hidden]` only sets display:none via the UA sheet, so .share__menu's own
   `display: flex` out-specified it and the panel rendered open on load. An
   author-level rule is required to make the attribute mean anything. */
.share__menu[hidden] { display: none !important; }

/* --- Filters: instant feel ------------------------------------------------
   The checkbox flips on click (optimistic), and the grid dims briefly while the
   new results arrive rather than the whole page blanking. */
.shop-facet__opt { transition: background .12s ease, color .12s ease; }
.shop-facet__opt .shop-facet__box { transition: background .12s ease, border-color .12s ease, transform .12s ease; }
.shop-facet__opt:active .shop-facet__box { transform: scale(.9); }
.shop-layout__main { transition: opacity .18s ease; }
.shop-layout__main.is-loading { opacity: .45; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
	.shop-layout__main, .shop-facet__opt, .shop-facet__box { transition: none; }
}

/* --- Featured grid: square gutters ---------------------------------------
   Row gap was 80px against a 24px column gap (32px / 24-vs-8 at the smaller
   breakpoints), so the rows floated far apart while the columns sat tight. One
   value on both axes at each size. */
.featured__grid { gap: var(--gap-md); }
@media (max-width: 900px) { .featured__grid { gap: var(--gap-md); } }
@media (max-width: 560px) { .featured__grid { gap: 8px; } }
