/* MOCHI — main stylesheet. Tokens from DESIGN_SYSTEM.md. */

:root {
	--color-primary: #141414;
	--color-secondary: #ffffff;
	--color-accent: #b4602e;
	--color-accent-hover: #9a4f26;
	--color-surface: #faf8f5;
	--color-surface-raised: #ffffff;
	--color-text-primary: #141414;
	--color-text-muted: #6b6560;
	--color-text-inverse: #faf8f5;
	--color-border: #d8d2c8;
	--color-border-subtle: #e8e4dc;
	--color-danger: #b23a2e;
	--font-display: "Tenor Sans", -apple-system, "Segoe UI", sans-serif;
	--font-body: "Outfit", -apple-system, "Segoe UI", sans-serif;
	--radius-base: 0px;
	--space: 8px;
	--dur-fast: 120ms;
	--dur-base: 200ms;
	--dur-slow: 320ms;
	--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
	--ease-in: cubic-bezier(0.7, 0, 0.84, 0);
}

* { box-sizing: border-box; }

/* WordPress core ships default global-styles CSS for .wp-element-button (a class WP/
   WooCommerce now add to buttons for theme.json compatibility). This theme has no
   theme.json, so reset that default here rather than fight it selector-by-selector. */
.wp-element-button {
	background: var(--color-primary);
	color: var(--color-text-inverse);
	border-radius: var(--radius-base);
	font-family: var(--font-body);
}

/* Site-wide horizontal-overflow guard (real bug, human-flagged from an actual phone,
   2026-08-27: text/images clipped at the left AND right edge on every content page —
   Contact Us, Our Story, FAQs, etc., not just the PDP). Confirmed live via
   document.documentElement.scrollWidth > clientWidth on desktop Chrome too (small but
   real, 7px), with the off-canvas cart/filter drawers (position:fixed + width:min(420px,
   100%) + transform:translateX(±100%) to hide them) and the accessibility skip-link
   (position:absolute; left:-9999px — the classic pattern accessibility guides
   specifically warn against for exactly this reason) both extending past the visible
   viewport. Desktop Chrome mostly optimizes fixed-position boxes out of the page's
   scrollable area, but mobile WebKit is well known to NOT always do the same — this is
   the standard, safe, catch-all fix regardless of which exact element does it on which
   browser: nothing on this site is ever meant to be horizontally scrollable, so clip it
   outright rather than chase every individual off-canvas element's exact browser
   quirk. */
html, body { overflow-x: hidden; max-width: 100%; }

body {
	margin: 0;
	background: var(--color-surface);
	color: var(--color-text-primary);
	font-family: var(--font-body);
	font-size: 16px;
	font-weight: 300;
	line-height: 1.6;
	-webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }

a { color: inherit; text-decoration: none; }

h1, h2, h3 {
	font-family: var(--font-display);
	font-weight: 400;
	text-transform: uppercase;
	margin: 0;
	line-height: 1.15;
}

/* Measured from reference: logo/H1/H2 all ~30-30.6px, not a large display scale. */
h1 { font-size: 30.6px; }
h2 { font-size: 30.6px; }
h3 { font-size: 20px; font-weight: 400; }

.container {
	max-width: 1500px;
	margin: 0 auto;
	padding: 0 calc(var(--space) * 3);
}

.label {
	font-size: 13px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	font-weight: 400;
}

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--space);
	background: var(--color-primary);
	color: var(--color-text-inverse);
	border: 1px solid var(--color-primary);
	border-radius: var(--radius-base);
	padding: 13px 20px;
	font-family: var(--font-body);
	font-size: 13px;
	letter-spacing: 3.9px;
	text-transform: uppercase;
	font-weight: 700;
	cursor: pointer;
	transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.btn:hover { background: transparent; color: var(--color-primary); }
.btn--accent { background: var(--color-accent); border-color: var(--color-accent); }
.btn--accent:hover { background: transparent; color: var(--color-accent); }
.btn--outline { background: transparent; color: var(--color-primary); }
.btn--outline:hover { background: var(--color-primary); color: var(--color-text-inverse); }
/* Ghost/outline-on-dark variant, measured from the reference hero CTA: transparent bg,
   1.3px white border/text over a photographic hero, filling solid white on hover. */
.btn--outline-white { background: transparent; color: #fff; border-color: #fff; border-width: 1.3px; }
.btn--outline-white:hover { background: #fff; color: var(--color-text-primary); }

/* ---------- Header / Nav ---------- */

.site-header {
	position: sticky;
	top: 0;
	z-index: 100;
	background: var(--color-surface-raised);
	border-bottom: 1px solid var(--color-border-subtle);
}

/* Reference behavior (measured on logoofficial.com): header is transparent with white
   text while it sits over the dark hero image, then swaps to a solid white bar with dark
   text once the page scrolls past the hero (their `is-light` class, toggled by scroll
   position). Only the front page has a dark full-bleed hero to float over — every other
   page keeps the always-solid header above, unchanged. `position:fixed` (not sticky)
   here because the header must overlap/float on top of the hero instead of pushing it
   down; JS (main.js) toggles `.is-scrolled` once the hero has scrolled past. */
body.home .site-header {
	position: fixed;
	top: 0; left: 0; right: 0;
	background: transparent;
	border-bottom-color: transparent;
	transition: background-color 0.25s ease, border-color 0.25s ease;
}
body.home .site-header .site-branding a,
body.home .site-header .header-icon-btn,
body.home .site-header .primary-nav a {
	color: #fff;
	transition: color 0.25s ease;
}
body.home .site-header.is-scrolled {
	background: var(--color-surface-raised);
	border-bottom-color: var(--color-border-subtle);
}
body.home .site-header.is-scrolled .site-branding a,
body.home .site-header.is-scrolled .header-icon-btn,
body.home .site-header.is-scrolled .primary-nav a {
	color: var(--color-text-primary);
}
/* header is out of flow (fixed) on the home page, so the hero must reserve the header's
   own height itself rather than relying on document flow to push it down — otherwise
   the hero's top ~129px renders underneath the (transparent, so invisible) header with
   nothing wrong visually, but the header's icon/nav hit-targets would sit directly on
   top of the hero's own content with no natural top offset. Hero already has enough
   height that this is a non-issue for the CTA position, but keep an explicit note here
   since it's easy to "fix" by accident later by re-adding top padding that would push
   the hero down and break the intentional overlap. */

.header-row {
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	padding: 20px calc(var(--space) * 3);
	gap: var(--space);
	min-height: 89px; /* header total ~129px incl. the 40px nav row below, measured */
}

.site-branding { grid-column: 2; text-align: center; }
.site-branding a {
	font-family: var(--font-display);
	font-size: 30px;
	font-weight: 400;
	text-transform: uppercase;
	letter-spacing: normal;
}

.header-actions { display: flex; align-items: center; justify-content: flex-end; gap: calc(var(--space) * 2); }
.header-icon-btn {
	background: none; border: 0; cursor: pointer; color: var(--color-text-primary);
	display: inline-flex; align-items: center; position: relative;
}
.cart-count {
	position: absolute; top: -6px; right: -8px;
	background: var(--color-accent); color: #fff;
	font-size: 10px; line-height: 1; border-radius: 50%;
	width: 16px; height: 16px; display: flex; align-items: center; justify-content: center;
}

.primary-nav { grid-column: 1 / -1; }
.primary-nav ul {
	list-style: none; margin: 0; padding: 0;
	display: flex; justify-content: center; gap: calc(var(--space) * 4);
	border-top: 1px solid var(--color-border-subtle);
	padding-top: 14px; padding-bottom: 14px;
}
.primary-nav a {
	font-family: var(--font-body);
	font-size: 15px; letter-spacing: 3px; text-transform: uppercase; font-weight: 300;
}
.primary-nav li { position: relative; }

.mega-menu {
	position: absolute; left: 50%; transform: translateX(-50%) translateY(8px);
	top: 100%; min-width: 480px;
	background: var(--color-surface-raised);
	border: 1px solid var(--color-border-subtle);
	box-shadow: 0 12px 32px rgba(20, 20, 20, 0.08);
	padding: calc(var(--space) * 3);
	display: grid; grid-template-columns: repeat(2, 1fr); gap: calc(var(--space) * 3);
	opacity: 0; visibility: hidden; pointer-events: none;
	transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.primary-nav li:hover .mega-menu,
.primary-nav li.is-open .mega-menu {
	opacity: 1; visibility: visible; pointer-events: auto; transform: translateX(-50%) translateY(0);
}
.mega-menu-group h4 { font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-text-muted); margin: 0 0 10px; font-family: var(--font-body); font-weight: 700; }
.mega-menu-group ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.mega-menu-group a { font-size: 14px; text-transform: none; letter-spacing: 0; font-weight: 400; }

/* ---------- Hero ---------- */

.hero {
	position: relative;
	min-height: 640px;
	display: flex; align-items: flex-end; justify-content: center;
	color: #fff; text-align: center; padding-bottom: 64px;
	overflow: hidden;
}
/* 2-slide hero slider (human request 2026-08-27 — reference itself runs a 2-slide hero,
   HOMEPAGE_RECONSTRUCTION_MAP.md §1 row 2). Cross-fade, not slide-in: both hero images
   are studio product shots at the same crop/scale, so a fade reads as "the light
   changed on the same kind of shot" rather than a jarring swap — simpler and safer than
   a translate-based slide given only 2 static background-image layers, no JS carousel
   library. Each .hero-slide carries its own background-image (was on .hero itself). */
.hero-slide {
	position: absolute; inset: 0;
	background-size: cover; background-position: center;
	opacity: 0; transition: opacity 1.2s ease;
	z-index: 0;
}
.hero-slide.is-active { opacity: 1; }
.hero::before {
	content: ""; position: absolute; inset: 0; z-index: 1;
	/* Shaded top AND bottom, not just bottom: the transparent overlay header (body.home
	   .site-header, above) needs guaranteed white-text legibility regardless of what's in
	   the hero photo — MOCHI's current hero is a light studio product shot (no lifestyle
	   photography supplied yet, see PROJECT_STATE.md pending work), not the reference's
	   dark moody photography, so contrast can't be assumed from the image alone. */
	background: linear-gradient(
		to bottom,
		rgba(0,0,0,0.4) 0%,
		rgba(0,0,0,0) 18%,
		rgba(0,0,0,0) 60%,
		rgba(0,0,0,0.5) 100%
	);
}
.hero-content { position: relative; z-index: 2; max-width: 640px; padding: 0 24px; }
.hero-content h1 { color: #fff; margin-bottom: 12px; }
.hero-content p { margin: 0 0 24px; font-size: 16px; opacity: 0.92; }
.hero-dots {
	position: absolute; z-index: 2; left: 50%; bottom: 20px; transform: translateX(-50%);
	display: flex; gap: 10px;
}
.hero-dot {
	width: 8px; height: 8px; border-radius: 50%; padding: 0;
	background: rgba(255,255,255,0.5); border: 1px solid rgba(255,255,255,0.8);
	cursor: pointer; transition: background var(--dur-fast) var(--ease-out);
}
.hero-dot.is-active { background: #fff; }

/* ---------- Section ---------- */

/* ROOT CAUSE FIX (2026-08-27, real mobile bug — human-flagged, confirmed via live
   getBoundingClientRect() measurement, not assumed): this used to be the shorthand
   `padding: calc(var(--space) * 8) 0;`. On `front-page.php` that's harmless — `.section`
   and `.container` are always two SEPARATE nested elements there
   (`<section class="section"><div class="container">`), so each rule only ever applies
   to its own element. But `index.php` (every plain content page — About Us, Our Story,
   FAQs, Contact Us, Terms & Policies, Privacy Policy, Track Your Order, How Can We
   Assist You) and `functions.php`'s WooCommerce wrapper (shop/PLP/PDP/cart/checkout,
   `woocommerce_output_content_wrapper`) both put `.container` AND `.section` on the SAME
   element. `.container`'s `padding: 0 24px` and this rule's old `padding: 64px 0` have
   equal specificity (both single classes) — same shorthand property, so whichever is
   declared LATER wins outright for all four sides, not just the ones that differ. Since
   this rule sits after `.container` in the file, its `0` for left/right was silently
   overriding `.container`'s 24px horizontal padding to zero on every one of those pages
   — invisible on desktop (the container's own `margin:0 auto` centering still leaves
   hundreds of pixels of gutter regardless), but genuinely 0px on mobile once the
   container goes full-width. Fixed by only ever setting the axis this rule actually
   owns (vertical) — it can no longer clobber `.container`'s (or anything else's)
   horizontal padding no matter which future markup combines the two classes. */
.section { padding-top: calc(var(--space) * 8); padding-bottom: calc(var(--space) * 8); }
.section-heading { text-align: center; margin-bottom: calc(var(--space) * 5); }
.section-heading .label { display: block; color: var(--color-accent); margin-bottom: 8px; }

/* ---------- Product grid / card ---------- */

.product-grid, ul.products {
	display: grid !important;
	grid-template-columns: repeat(4, 1fr);
	gap: 22px; /* measured reference gutter */
	list-style: none; margin: 0 !important; padding: 0 !important;
}
/* WooCommerce core ships `ul.products::before,::after{content:" ";display:table}` — a
   clearfix left over from its own float-based grid. Once `ul.products` is display:grid
   (above), these pseudo-elements become real grid items too (display:table is a valid
   generated-box display value), silently consuming the FIRST grid cell and pushing every
   real <li> over by one slot — confirmed live: with 4 products in a 4-column row, this
   left column 1 of row 1 empty and wrapped the 4th product down into a near-empty
   second row (human-reported blank space below Related Products, and a missing/blank
   first image in Recently Viewed — same root cause in both). */
.product-grid::before, .product-grid::after,
ul.products::before, ul.products::after { content: none !important; display: none !important; }
.product-card, ul.products li.product {
	position: relative;
	width: auto !important;
	float: none !important;
	margin: 0 !important;
}
ul.products li.product a {
	display: block;
}
.product-card-media img, ul.products li.product a img {
	/* Was `.product-card-media` (the <a> wrapper) instead of `.product-card-media img` —
	   aspect-ratio/object-fit only do anything on the actual <img>, so on the homepage's
	   cards (<a class="product-card-media"><img></a>) this rule was styling the wrapper
	   and never touching the image at all. Confirmed live: the <img> sat at its own
	   natural-ratio auto-height (top-aligned, ~87px short of the 2:3 box), leaving a
	   visible gray gap at the bottom of the card and reading as a badly-cropped/zoomed
	   product photo — human-reported "images theek nahi lagi" (images don't look
	   right). WC's own loop (ul.products li.product a img) was never affected — its
	   selector already targeted the <img> directly, which is why PLP looked fine while
	   the homepage grids didn't.

	   Product-card framing fix (2026-08-29): root-caused live — every source photo is
	   1122×1402, exactly 4:5, confirmed by reading get_post_thumbnail attachment
	   metadata directly, not assumed. The frame here was 2:3 (taller than 4:5), so
	   every card cropped some of the photo away regardless of composition — angled
	   3/4-view shots (already tightly framed around the product with little margin,
	   e.g. Hunza/Skardu) lost visible product into that crop, while top-down shots
	   with generous negative space (e.g. Chitral/Naran) had enough margin to absorb
	   the same crop invisibly, reading as "inconsistent" even though the same rule
	   applied to all. Frame changed to 4:5 — the images' own native ratio — so cover
	   and contain now produce the same result (no aspect mismatch left to crop), and
	   object-fit switched to contain anyway as the explicit non-cropping choice per
	   the human's stated preference, with a neutral surface-toned background for any
	   sub-pixel rounding sliver rather than the previous cooler gray-ish border tone. */
	position: relative; aspect-ratio: 4 / 5; object-fit: contain;
	background: var(--color-surface);
	width: 100% !important;
	height: auto !important;
	max-width: none;
}
.product-card-media,
ul.products li.product a.woocommerce-loop-product__link { position: relative; overflow: hidden; display: block; }
/* Client task (2026-09-01): Quick View "must be same design & POSITION as Home page" —
   root-caused live: Home's `.product-card-media` wraps ONLY the <img>, so `.quick-view`
   (position:absolute;bottom:0 — see below) pins to the bottom of the IMAGE. WooCommerce's
   default loop template wraps image+title+price all inside ONE anchor
   (`a.woocommerce-loop-product__link`, already position:relative above for that same
   anchor), and this theme's quick-view trigger renders inside that same anchor — so on
   Shop/Category/related-products/Recently-Viewed it was pinning to the bottom of the
   WHOLE CARD (visibly covering the price) instead of the image, confirmed live via a
   screenshot showing the black bar sitting under the title where price used to be.
   `.mochi-loop-media` (functions.php mochi_loop_media_open/close) wraps just the
   thumbnail on the WC loop, giving `.quick-view` a nearer positioned ancestor scoped to
   the image only — CSS absolute positioning always binds to the closest positioned
   ancestor, so this alone (no JS/PHP position math) restores the Home-identical
   image-only overlay position without touching the outer anchor rule above. */
.mochi-loop-media { position: relative; overflow: hidden; display: block; }
.product-card .quick-view, ul.products li.product .quick-view {
	position: absolute; left: 0; right: 0; bottom: 0; cursor: pointer;
	background: var(--color-primary); color: var(--color-text-inverse);
	text-align: center; padding: 8px; font-family: var(--font-body); font-size: 13.6px;
	letter-spacing: normal; text-transform: none; font-weight: 300;
	opacity: 0; transform: translateY(8px);
	transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.product-card:hover .quick-view, ul.products li.product:hover .quick-view { opacity: 1; transform: translateY(0); }
.product-card .sale-badge, span.onsale {
	position: absolute; top: 10px; left: 10px; z-index: 2;
	background: var(--color-danger); color: #fff; font-size: 11px; text-transform: uppercase;
	padding: 4px 8px; letter-spacing: 0.04em;
}
/* Finalization Stage 1: centered title/price (spec: "Select Options" removed, card
   reads as IMAGE / TITLE / PRICE, title+price centered). Applies to both the
   homepage's custom cards and the standard WC loop via the same combined selector this
   file already uses throughout for card styling — one rule, not a per-listing patch. */
/* Client task (2026-09-01): "product cards must match Home page exactly on every
   listing page" — root-caused live via computed-style + matched-rule inspection (not
   guessed): WooCommerce core's own woocommerce.css ships
   `.woocommerce ul.products li.product .woocommerce-loop-product__title` (font-size:1em)
   and `.woocommerce ul.products li.product .price` (color + font-weight), each with
   exactly ONE more class of specificity than this theme's un-prefixed
   `ul.products li.product X` rules below — confirmed live (Shop page): title rendered at
   16px instead of the intended 14px, price rendered in WC core's default olive/yellow
   (rgb(149,142,9)) at font-weight 400 instead of this theme's dark
   var(--color-text-primary) at weight 300, while the identical rule already applied
   correctly on Home page's `.product-card-*` classes (no competing WC-core rule exists
   for those custom class names). Fixed the idiomatic WooCommerce way — matching core's
   own `.woocommerce` prefix so the theme's rule is never lower-specificity than core's,
   with no !important needed. */
.product-card-title, .woocommerce ul.products li.product .woocommerce-loop-product__title {
	font-size: 14px; text-transform: uppercase; letter-spacing: 2.8px; margin: 14px 0 4px;
	font-family: var(--font-display); font-weight: 400; text-align: center;
}
.product-card-price, .woocommerce ul.products li.product .price {
	font-size: 13.6px; font-family: var(--font-body); font-weight: 300; color: var(--color-text-primary);
	text-align: center;
}
.placeholder-badge {
	display: inline-block; font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase;
	background: #fff3e8; color: var(--color-accent); border: 1px solid var(--color-accent);
	padding: 2px 6px; border-radius: var(--radius-base); margin-top: 6px;
}

/* ---------- Editorial banner (HOMEPAGE_RECONSTRUCTION_MAP.md #7/#10) ----------
   Reference reuses ONE full-bleed-image + large-centered-heading component twice
   ("OPIA BY LOGO", "MARK DOWN") to break up grid rhythm — measured height ~673px,
   heading vertically/horizontally centered, no product grid, no visible button.
   MOCHI uses this component once, for the Father+Son statement (see map §2 — the
   reference's 2nd use needs real markdown pricing MOCHI doesn't have yet). Product
   photo standing in for lifestyle photography (known gap, matches the hero). */
.editorial-banner {
	position: relative;
	min-height: 560px;
	display: flex; align-items: center; justify-content: center;
	background-size: cover; background-position: center;
	text-align: center;
}
.editorial-banner::before {
	content: ""; position: absolute; inset: 0;
	background: rgba(20, 20, 20, 0.32); /* even wash, not a gradient — the whole heading needs to read, not just top or bottom like the hero's CTA-only legibility need */
}
.editorial-banner h2 {
	position: relative; z-index: 1;
	color: #fff; font-size: 48px; line-height: 1.2; margin: 0;
	text-shadow: 0 2px 12px rgba(0,0,0,0.25);
}

/* ---------- Brand story / About Us (HOMEPAGE_RECONSTRUCTION_MAP.md #12) ----------
   Reference: split layout, text column + a staggered/overlapping pair of images in the
   second column (different heights, offset vertically) — NOT the single flat
   solid-color centered-text band this used to be. */
.brand-story { padding: calc(var(--space) * 10) 0; }
.brand-story-grid {
	display: grid; grid-template-columns: 1fr 1fr; gap: calc(var(--space) * 6);
	align-items: center;
}
.brand-story-text { text-align: left; }
.brand-story-text .label { color: var(--color-accent); }
.brand-story-text h2 { margin: 16px 0 20px; }
.brand-story-text p { max-width: 480px; margin: 0 0 20px; color: var(--color-text-muted); }
.brand-story-text .accent-rule { width: 48px; height: 2px; background: var(--color-accent); margin: 0 0 24px; }
.brand-story-images { position: relative; }
.brand-story-image { width: 68%; aspect-ratio: 3/4; object-fit: cover; }
.brand-story-image--a { position: relative; z-index: 1; }
.brand-story-image--b { position: absolute; right: 0; top: 15%; z-index: 0; }

/* ---------- Footer ---------- */

.site-footer { border-top: 1px solid var(--color-border-subtle); padding: calc(var(--space) * 7) 0 calc(var(--space) * 4); margin-top: calc(var(--space) * 6); }
.footer-grid {
	display: grid; grid-template-columns: 1.4fr 1fr 1fr 1.2fr; gap: calc(var(--space) * 4);
	margin-bottom: calc(var(--space) * 5);
}
.footer-grid h4 { font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; margin: 0 0 14px; }
.footer-grid ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; font-size: 14px; color: var(--color-text-muted); }
.footer-grid ul a { color: var(--color-text-muted); }
.footer-meta { font-size: 14px; color: var(--color-text-muted); line-height: 1.8; }
.newsletter-form { display: flex; margin-top: 14px; }
.newsletter-form input { flex: 1; border: 1px solid var(--color-border); border-right: 0; padding: 10px 12px; font-family: var(--font-body); background: var(--color-surface-raised); }
.newsletter-form button { border: 1px solid var(--color-primary); background: var(--color-primary); color: #fff; padding: 0 16px; cursor: pointer; }
.newsletter-status { font-size: 12px; color: var(--color-text-muted); margin: 8px 0 0; min-height: 1em; }
.footer-copy { text-align: center; font-size: 13px; color: var(--color-text-muted); padding-top: calc(var(--space) * 3); border-top: 1px solid var(--color-border-subtle); }

/* ---------- Cart drawer ---------- */

.cart-drawer-overlay {
	position: fixed; inset: 0; background: rgba(20,20,20,0.4);
	opacity: 0; visibility: hidden; transition: opacity var(--dur-base) var(--ease-out);
	z-index: 200;
}
.cart-drawer {
	/* Task 1 (2026-08-29), visual polish pass #2: narrower (was 420px — human-flagged
	   "too wide/heavy") — 380px is still comfortable for a 3-4 word product name plus
	   a qty/price row without wrapping awkwardly, closer to the benchmark's own
	   proportions relative to viewport. */
	position: fixed; top: 0; right: 0; bottom: 0; width: min(380px, 100%);
	background: var(--color-surface-raised); z-index: 201;
	transform: translateX(100%);
	transition: transform var(--dur-base) var(--ease-out);
	display: flex; flex-direction: column;
	box-shadow: -12px 0 32px rgba(20,20,20,0.12);
}
body.cart-drawer-open .cart-drawer-overlay { opacity: 1; visibility: visible; }
/* Real bug found live while verifying Task 2 (mutual exclusion): the filter drawer's
   own element also carries the shared `.cart-drawer` class (for its base positioning/
   sizing/transition rules — see `.filter-drawer` below, which only overrides side and
   direction). A plain `.cart-drawer` selector here therefore matched BOTH elements,
   so opening the cart also forced the filter drawer's transform to translateX(0) —
   the root cause of the *original* "both drawers open at once" report, just newly
   exposed as a one-way leak once mutual exclusion made the two states no longer
   overlap. Scoped to the actual cart drawer's own id so it can never affect the
   filter drawer, which shares the class but not the id. */
body.cart-drawer-open #mochi-cart-drawer { transform: translateX(0); }
/* Human visual QA correction (2026-08-29): drawer content was sitting too close to
   the left/right edges — inconsistently, since the header/footer used one padding
   value, the cart's own row list another, and the filter drawer's content (which
   renders straight into .cart-drawer-body with no wrapper of its own) had NO
   horizontal padding at all. ONE gutter variable now drives every horizontal inset in
   both drawers — header, body (covers the filter drawer directly, and is the outer
   inset cart's own inner wrapper sits within), and footer/buttons — so nothing is
   glued to the edge and nothing needed a one-off margin on an individual element. */
:root { --drawer-gutter: 24px; }
@media (max-width: 480px) { :root { --drawer-gutter: 18px; } }

.cart-drawer-header { flex-shrink: 0; display: flex; align-items: center; justify-content: space-between; padding: 20px var(--drawer-gutter); border-bottom: 1px solid var(--color-border-subtle); }
.cart-drawer-header h2 { font-family: var(--font-display); font-size: 14px; font-weight: 400; letter-spacing: 0.15em; text-transform: uppercase; }
.cart-drawer-close { background: none; border: 0; cursor: pointer; font-size: 18px; color: var(--color-text-muted); line-height: 1; }
.cart-drawer-close:hover { color: var(--color-text-primary); }
/* Targeted fix (2026-08-29): only the line-item list scrolls — subtotal/View
   Cart/Checkout stay pinned and reachable regardless of cart size ("footer actions
   reachable" requirement). WooCommerce's own mini-cart markup (items, total, buttons)
   all comes back as one block from woocommerce_mini_cart() — no template override
   needed, this is a pure flex-layout split of the existing DOM structure. */
.cart-drawer-body { flex: 1; overflow: hidden; padding: 0 var(--drawer-gutter); display: flex; flex-direction: column; }
.widget_shopping_cart_content { flex: 1; display: flex; flex-direction: column; min-height: 0; }
/* Horizontal gutter now comes from .cart-drawer-body above — these are vertical-only
   so it isn't applied twice (was 24px all around on the list, redundant with the
   drawer-body inset once that existed). */
.widget_shopping_cart_content ul.woocommerce-mini-cart { flex: 1; overflow-y: auto; padding: 22px 0; margin: 0; }
.widget_shopping_cart_content .woocommerce-mini-cart__empty-message { padding: 22px 0; }
.widget_shopping_cart_content .woocommerce-mini-cart__total,
.widget_shopping_cart_content .woocommerce-mini-cart__buttons { flex-shrink: 0; }
.widget_shopping_cart_content .woocommerce-mini-cart__buttons { padding-bottom: var(--drawer-gutter); }
.cart-drawer-footer { padding: 24px; border-top: 1px solid var(--color-border-subtle); }

/* Targeted fix (2026-08-29): human QA reported the drawer's top/header looking cut —
   root cause is the WordPress admin bar (fixed, z-index 99999, only visible to logged-in
   staff/QA, never real customers) sitting on top of the drawer's own top:0 position.
   Offset by the admin bar's own documented height instead of fighting it with z-index. */
body.admin-bar .cart-drawer-overlay,
body.admin-bar .cart-drawer,
body.admin-bar .filter-drawer { top: 32px; }
@media (max-width: 782px) {
	body.admin-bar .cart-drawer-overlay,
	body.admin-bar .cart-drawer,
	body.admin-bar .filter-drawer { top: 46px; }
}

/* Drawer quantity [-]/[+] (targeted fix #3, 2026-08-29; enlarged into a unified
   bordered "pill" in the visual-polish pass — human-flagged as "too small/
   disconnected" at the original 22px, borderless-between-buttons size). */
.mochi-mini-cart-qty { display: flex; align-items: center; margin-top: 2px; }
.mochi-qty-btn {
	width: 28px; height: 28px; line-height: 1;
	border: 1px solid var(--color-border); background: none; cursor: pointer;
	font-size: 14px; display: flex; align-items: center; justify-content: center;
	padding: 0; color: var(--color-text-primary);
}
.mochi-qty-minus { border-radius: var(--radius-base) 0 0 var(--radius-base); border-right: 0; }
.mochi-qty-plus { border-radius: 0 var(--radius-base) var(--radius-base) 0; border-left: 0; }
.mochi-qty-btn:hover { background: var(--color-surface); }
.mochi-qty-value {
	min-width: 28px; height: 28px; text-align: center; font-size: 13px;
	border-top: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border);
	display: flex; align-items: center; justify-content: center;
}
.mochi-qty-price { margin-left: 14px; color: var(--color-text-primary); font-size: 13px; font-weight: 500; }
.mochi-mini-cart-qty.is-loading { opacity: 0.5; pointer-events: none; }

/* Checkout Order Summary quantity (Task 1, 2026-08-29) — reuses .mochi-qty-btn/
   .mochi-qty-value styling above so the drawer and checkout steppers look identical;
   only the wrapper's own spacing differs to fit the Order Summary row layout. */
.mochi-checkout-qty { display: flex; align-items: center; gap: 8px; margin-top: 4px; }
.mochi-checkout-qty.is-loading { opacity: 0.5; pointer-events: none; }

/* ---------- Checkout visual polish (Task 2, 2026-08-29) ---------- */
/* Presentation only — no functional change, no rebuild. WooCommerce Blocks' own
   default spacing/typography is generous to a fault next to the rest of this theme's
   tighter, sharper-edged language (0px radius, Tenor Sans headings, Outfit body) — this
   brings the checkout in line with that without touching the block's own DOM/markup. */

/* Section headings ("Contact information", "Billing address", "Payment options") —
   match the brand's display font/letter-spacing already used for "CHECKOUT" itself,
   with tighter spacing around them than the block default. */
.wc-block-components-checkout-step__title {
	font-family: var(--font-display);
	font-size: 15px;
	font-weight: 400;
	letter-spacing: 0.15em;
	text-transform: uppercase;
	margin-bottom: 16px;
}
.wc-block-components-checkout-step { margin-bottom: 28px; }

/* Form fields — WC Blocks' default input height/margins run noticeably looser than
   this theme's own forms (compare Ask a Question / Contact Us, both tighter). Sharp
   corners to match --radius-base, tighter row gaps. */
.wc-block-components-text-input input,
.wc-block-components-address-form select,
.wc-block-components-country-input .components-combobox-control__input {
	border-radius: var(--radius-base);
	border-color: var(--color-border);
	padding-top: 14px;
	padding-bottom: 10px;
}
.wc-block-components-text-input,
.wc-block-components-address-form .components-base-control { margin-bottom: 12px; }

/* Order Summary — compact rows, clearer separation from the coupon/totals block below
   it, consistent right-aligned prices (already the default, reinforced here). */
.wc-block-components-order-summary { border-top: none; }
.wc-block-components-order-summary-item { padding: 12px 0; }
.wc-block-components-panel,
.wc-block-components-totals-item { border-top: 1px solid var(--color-border-subtle); }
.wc-block-components-totals-item { padding: 10px 0; }
.wc-block-components-totals-item__label { color: var(--color-text-muted); font-size: 14px; }
.wc-block-components-totals-footer-item .wc-block-components-totals-item__label,
.wc-block-components-totals-footer-item .wc-block-components-totals-item__value {
	color: var(--color-text-primary);
	font-weight: 600;
	font-size: 16px;
}

/* Task 3 (2026-08-29), visual polish pass #2: column proportions + payment-area
   spacing. WC Blocks' own grid already splits fields/summary sensibly — this only
   tightens the gap between them (was reading a touch loose next to the rest of the
   theme's tighter spacing) and gives the payment method options (currently just COD)
   clearer selected-state framing instead of the default thin/flat outline. */
.wc-block-checkout__main { padding-right: 12px; }
.wc-block-checkout__sidebar { padding-left: 12px; }
/* Task 3 polish (2026-08-29): a first attempt added padding directly to
   .wc-block-components-radio-control__option, which clipped/overlapped the radio
   label against the icon (that element's internal layout relies on its own default
   padding for the icon/label positions) — confirmed live, reverted immediately.
   border-radius alone (sharp corners matching --radius-base) is safe since it doesn't
   touch internal spacing. */
.wc-block-components-radio-control__option { border-radius: var(--radius-base); }
.wc-block-components-payment-method-label { font-family: var(--font-body); font-weight: 500; }

/* ---------- Quick View modal ---------- */
/* Centered modal (not a side drawer like cart/filter) — this is a product preview, not a
   list of items, so the reference's own pattern (and every common Quick View pattern) is
   a centered dialog over a dimmed backdrop. Reuses .summary/.product_title/.variations
   etc. class names inside quick-view-summary so the PDP's own CSS rules apply to the
   AJAX-loaded fragment without duplicating them. */
.quick-view-overlay {
	position: fixed; inset: 0; background: rgba(20,20,20,0.5);
	opacity: 0; visibility: hidden; transition: opacity var(--dur-base) var(--ease-out);
	z-index: 200;
}
.quick-view-modal {
	position: fixed; top: 50%; left: 50%;
	transform: translate(-50%, -50%) scale(0.96);
	width: min(880px, 92vw); max-height: 88vh; overflow-y: auto;
	background: var(--color-surface-raised); z-index: 201;
	opacity: 0; visibility: hidden; pointer-events: none;
	transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
	box-shadow: 0 24px 64px rgba(20,20,20,0.18);
	display: grid; grid-template-columns: 1fr 1fr; gap: calc(var(--space) * 5);
	padding: calc(var(--space) * 5);
}
body.quick-view-open .quick-view-overlay { opacity: 1; visibility: visible; }
body.quick-view-open .quick-view-modal {
	opacity: 1; visibility: visible; pointer-events: auto;
	transform: translate(-50%, -50%) scale(1);
}
.quick-view-close {
	position: absolute; top: calc(var(--space) * 2); right: calc(var(--space) * 2);
	background: none; border: 0; cursor: pointer; font-size: 22px; line-height: 1;
	z-index: 1;
}
/* The AJAX fragment (functions.php mochi_quick_view_ajax) wraps its media/summary pair
   in <div class="woocommerce"><div class="product type-product"> purely so the existing
   PDP rules scoped to ".woocommerce div.product ..." (button color, variations table,
   select-hiding, etc.) apply inside the modal too — the modal can open from pages that
   never get the `.woocommerce` body class (e.g. the homepage). display:contents on all
   3 wrapper levels means those wrapper divs don't create their own grid cells — the
   actual .quick-view-media / .quick-view-summary still act as this modal's two direct
   grid items, same as if they had no wrapper at all. */
.quick-view-body,
.quick-view-body > .woocommerce,
.quick-view-body > .woocommerce > .product { display: contents; }
.quick-view-media img { width: 100%; aspect-ratio: 2/3; object-fit: cover; }
.quick-view-summary .product_title { font-size: 24px; margin-bottom: 8px; }
.quick-view-full-link { margin-top: 16px; }
.quick-view-full-link a { font-size: 13px; text-decoration: underline; color: var(--color-text-muted); }
.quick-view-loading { grid-column: 1 / -1; text-align: center; padding: calc(var(--space) * 6) 0; color: var(--color-text-muted); }
@media (max-width: 640px) {
	.quick-view-modal { grid-template-columns: 1fr; width: 92vw; padding: calc(var(--space) * 3); }
}

/* ---------- Mobile nav toggle ---------- */

.mobile-nav-toggle { display: none; background: none; border: 0; cursor: pointer; }

/* ---------- Responsive ----------
   Width-based mobile overrides live at the END of this file now, not here — see that
   section for why (real human phone-testing, 2026-08-27, found the PDP still 2-column
   and the gallery thumbnail rail still an 80px-wide absolute column on an actual mobile
   viewport, despite this file already having mobile rules for exactly that). Only the
   width-independent reduced-motion query stays in its original place below; it never had
   this problem since nothing later in the file also targets that selector. */

@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after { transition-duration: 1ms !important; animation-duration: 1ms !important; }
}

/* Was `left: -9999px` — the classic off-screen-hide technique, but it's specifically
   flagged in accessibility guides (and confirmed live here, see the html/body
   overflow-x comment above) as a real cause of page-wide horizontal scroll on real
   mobile browsers: the element still occupies that -9999px position in the document's
   layout, so its box can extend the page's scrollable area even though nothing ever
   scrolls that far in practice. Standard "visually hidden" pattern instead: collapse
   the box to 1x1px and clip it, so it can't contribute any horizontal extent at all,
   still fully readable/focusable for screen readers and keyboard users. */
.skip-link {
	position: absolute; left: 12px; top: 0;
	width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
	white-space: nowrap;
	background: var(--color-primary); color: #fff;
	padding: 12px 20px; z-index: 999;
}
.skip-link:focus {
	width: auto; height: auto; overflow: visible; clip: auto; clip-path: none;
	white-space: normal;
	top: 12px;
}

:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

/* ---------- WooCommerce: shop archive / filters ---------- */

.woocommerce-main { padding-top: calc(var(--space) * 5); }
.woocommerce-result-count, .woocommerce-ordering { font-size: 13px; color: var(--color-text-muted); }
.woocommerce-ordering select { border: 1px solid var(--color-border); padding: 8px 12px; font-family: var(--font-body); background: var(--color-surface-raised); }

/* Filter drawer reuses .cart-drawer's base but slides from the left. */
.filter-drawer { left: 0; right: auto; transform: translateX(-100%); box-shadow: 12px 0 32px rgba(20,20,20,0.12); }
body.filter-drawer-open .filter-drawer { transform: translateX(0); }
body.filter-drawer-open #mochi-filter-overlay { opacity: 1; visibility: visible; }
.mochi-filter-group { border-top: 1px solid var(--color-border-subtle); padding: 16px 0; }
.mochi-filter-group:first-child { border-top: 0; padding-top: 0; }
.mochi-filter-group h4 { font-size: 13px; text-transform: uppercase; letter-spacing: 0.05em; margin: 0 0 12px; }

.mochi-filter-toggle {
	display: inline-flex; align-items: center; gap: 8px;
	border: 1px solid var(--color-border); background: var(--color-surface-raised);
	padding: 10px 18px; cursor: pointer; font-size: 13px; letter-spacing: 0.03em;
	margin-bottom: calc(var(--space) * 3);
}
.woocommerce-widget-layered-nav, .widget_price_filter, .widget_layered_nav_filters {
	border-top: 1px solid var(--color-border-subtle); padding: 16px 0; margin: 0;
}
.woocommerce-widget-layered-nav ul, .widget_layered_nav_filters ul { list-style: none; margin: 0; padding: 0; }
.woocommerce-widget-layered-nav li { padding: 4px 0; font-size: 14px; }

/* ---------- WooCommerce: single product ---------- */

/* 50/50 gallery/info split, measured from reference (~721px each of a 1442px inner width).
   IMPORTANT: this grid must live on div.product itself, NOT on .woocommerce-main — the
   direct children of .woocommerce-main are <nav class="woocommerce-breadcrumb">,
   <div class="woocommerce-notices-wrapper"> and a SINGLE <div class="product ...">
   wrapper (which itself contains the gallery + summary + tabs + related-products).
   Putting the grid on .woocommerce-main split THOSE three unrelated siblings into two
   columns instead, so div.product only ever received half the page width (~726px of
   1500px) — collapsing the whole PDP into one narrow column with a dead-blank second
   column beside it. The gallery/summary split belongs one level deeper, on div.product's
   own children. */
.single-product div.product {
	display: grid;
	grid-template-columns: 1fr 1fr;
	column-gap: calc(var(--space) * 6);
	row-gap: 0;
	align-items: start;
}
.single-product div.product > .woocommerce-product-gallery { grid-column: 1; grid-row: 1; }
.single-product div.product > .summary.entry-summary { grid-column: 2; grid-row: 1; }
/* Tabs, related-products, recently-viewed, and reviews are also direct children of
   div.product (all hooked to woocommerce_after_single_product_summary) — without an
   explicit span they'd auto-place two-per-row into the 2-column grid instead of each
   running full-width below the gallery/summary row. Confirmed live: recently-viewed and
   reviews were landing in the SAME row, side by side (sharing one column each) before
   this was added — same root-cause pattern as the tabs/related-products fix above. */
.single-product div.product > .woocommerce-tabs,
.single-product div.product > .related.products,
.single-product div.product > .mochi-recently-viewed,
.single-product div.product > .mochi-reviews-section {
	grid-column: 1 / -1;
}
.woocommerce div.product div.images { margin: 0; }
/* Task 4 (2026-08-29) — global-scale diagnosis, PDP gallery specifically: root-caused
   live (not guessed) via getBoundingClientRect on the actual rendered <img> — at the
   even 1fr/1fr gallery/summary column split (~700px+ gallery column in a 1500px
   container), the 2:3 aspect-ratio produces a ~910px-tall image against a typical
   ~660-900px viewport. The image itself was NOT over-cropped (the source photo has
   generous negative space, confirmed by downloading and viewing the actual file) —
   it just didn't fit the viewport, so only its top portion was visible without
   scrolling, reading as an extreme close-up ("zoomed in / in-your-face"). Capping
   height keeps the 2:3 ratio (still matches the measured reference spec, unchanged)
   while never letting the image outgrow a comfortable viewport-relative size — scoped
   to the PDP gallery only, no effect on product-grid cards, hero, drawer, or checkout
   thumbnails, each of which keeps its own intended scale per this task's brief. */
.woocommerce div.product div.images img {
	/* Corrected per explicit human review: the first attempt kept `object-fit: cover`
	   with a forced 2:3 `aspect-ratio`, which still crops the photo — just at a smaller
	   rendered size — not what was asked ("must remain fully visible, should NOT be
	   cropped just to preserve a forced frame"). Dropping the forced ratio entirely: the
	   image now renders at its own natural proportions (the source photos are ~4:5, a
	   generously-framed studio shot, confirmed by viewing the actual file), scaled down
	   only by `max-height` — full product always visible, no object-fit crop at all. */
	border-radius: var(--radius-base);
	max-height: 72vh;
	max-width: 100%;
	width: auto;
	height: auto;
	margin: 0 auto;
	display: block;
}

/* WooCommerce's own Related Products template outputs a bare, unstyled <h2> — no theme
   rule ever targeted `.related.products h2` before, so it fell back to the browser
   default (left-aligned, plain body font). Human-flagged: reference's equivalent
   section ("FREQUENTLY BOUGHT TOGETHER") is centered, matching every other section
   heading on the site (.section-heading is always centered — see main.css §Section).
   Also had no side padding/max-width at all (edge-to-edge, unlike every other section
   which sits inside .container) — added to match. */
.related.products {
	max-width: 1500px; margin: 0 auto;
	padding: calc(var(--space) * 8) calc(var(--space) * 3);
}
.related.products h2 { text-align: center; margin: 0 0 calc(var(--space) * 5); }

/* WooCommerce core (woocommerce-layout.css) still ships its own float-based 48%-width
   two-column product layout (`div.product div.images{width:48%}`,
   `div.product div.summary{width:48%;float:right}`), and .woocommerce-product-gallery
   itself carries WooCommerce's own `.images` class. Those core rules load before this
   stylesheet but the descendant selector `.woocommerce #content div.product div.summary`
   is higher-specificity than a plain class override, so an un-!important reset doesn't
   reliably win. Left unset, a grid item sized to a 48%-of-its-track width still only
   paints 48% of that track, leaving the other ~52% of each column as dead whitespace and
   shrinking FlexSlider's own JS-computed gallery width to match. */
.single-product div.product > .woocommerce-product-gallery,
.single-product div.product > div.images,
.single-product div.product > div.summary,
.single-product div.product > .summary.entry-summary {
	float: none !important;
	width: 100% !important;
}

/* Vertical thumbnail column BESIDE the main image, not a horizontal strip below it
   (measured: reference's product__thumbs--beside is an ~80px-wide column to the left
   of the main image, full gallery height). Uses float, not flex/grid, on the gallery
   root — FlexSlider (which powers .flex-viewport) computes its own width via JS at
   init and fights with flex/grid reflow on its parent; floating the thumbs column and
   giving the viewport a matching margin leaves FlexSlider's own layout math alone. */
/* .woocommerce-product-gallery is already position:relative (WooCommerce core) and
   float:left (its own 2-col image/summary layout) — thumbs come AFTER .flex-viewport
   in FlexSlider's DOM, so a float on thumbs would drop below the (taller) viewport
   instead of sitting beside it. Absolute-positioning the thumbs column sidesteps both
   that source-order issue and the earlier flex/FlexSlider width-calculation conflict. */
.woocommerce-product-gallery { padding-left: 92px; }
.woocommerce-product-gallery .flex-control-thumbs {
	position: absolute; left: 0; top: 0; width: 80px;
	list-style: none; display: flex; flex-direction: column; gap: 10px; padding: 0; margin: 0;
}
.woocommerce-product-gallery .flex-viewport { margin-left: 0; }
/* WooCommerce core (woocommerce.css) ships `.flex-control-thumbs li{width:25%;float:left}`
   sized for its own default HORIZONTAL thumb strip — with this rail's real column
   width (80px) that rendered each thumbnail at ~20px, effectively invisible (human-
   reported "thumbnails are very small", confirmed live: 20x30px rendered vs. the
   reference's measured 76x114px). Equal specificity to core's rule and loading later in
   the same file still wasn't enough to win here — same cascade behavior already hit and
   documented for `.variations select` above; !important again, verified live this time
   (20px -> 80px) rather than assumed. */
.flex-control-thumbs li { width: 100% !important; float: none !important; }
.flex-control-thumbs img { border: 1px solid var(--color-border-subtle); cursor: pointer; aspect-ratio: 2/3; object-fit: cover; width: 100%; }
.flex-control-thumbs img.flex-active { border-color: var(--color-primary); }

.woocommerce div.product .product_title { font-size: 30.6px; margin-bottom: 8px; }
.woocommerce div.product p.price, .woocommerce div.product span.price { font-size: 16px; font-weight: 300; color: var(--color-text-primary); font-family: var(--font-body); }
.woocommerce div.product .woocommerce-product-details__short-description { color: var(--color-text-muted); margin: 16px 0; }

.woocommerce div.product form.cart { margin-top: 24px; }
.woocommerce div.product form.cart .variations { width: 100%; margin-bottom: 20px; }
.woocommerce div.product form.cart .variations td, .woocommerce div.product form.cart .variations th { display: block; padding: 0; }
.woocommerce div.product form.cart .variations label { display: block; font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 10px; color: var(--color-text-muted); }
.woocommerce form.cart .variations select { display: none !important; } /* replaced by mochi-size-swatches JS — scoped to form.cart+.variations only (not div.product) so this also applies inside the Quick View modal's AJAX-injected form, which isn't nested in a div.product. !important: WooCommerce core's own `.variations select` rule (woocommerce.css) was observed still winning over an equal/higher-specificity un-!important override here — verified live, not assumed. */

.mochi-size-swatches { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 20px; }
.mochi-size-swatch {
	min-width: 44px; height: 30px; padding: 0 10px;
	border: 1px solid var(--color-border); background: var(--color-surface-raised);
	font-family: var(--font-body); font-size: 16px; font-weight: 400; cursor: pointer;
	display: inline-flex; align-items: center; justify-content: center;
	transition: border-color var(--dur-fast) var(--ease-out);
}
.mochi-size-swatch:hover { border-color: var(--color-primary); }
.mochi-size-swatch.is-selected { border-color: var(--color-primary); background: var(--color-primary); color: #fff; }
.mochi-size-swatch:disabled { opacity: 0.35; cursor: not-allowed; }

/* Prototype correction (2026-09-01): real color swatches, distinct from the plain-text
   Size treatment above — a swatch shows the color itself (admin-editable per term, see
   functions.php mochi_get_color_swatch_hex), and needs a genuinely different visual for
   "visible but currently unavailable" (state B without C — a real color this product's
   range includes, with no real variation yet) than Size's simple disabled-fade, per the
   explicit requirement to distinguish those two things rather than reuse one style for
   both. The neutral 1px outer ring (not a color-matched border) keeps every swatch
   readable against both a light and a dark page background regardless of the swatch's
   own color — a pale swatch like white would otherwise disappear on this page's own
   off-white background without it. */
.mochi-color-swatches { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 20px; }
.mochi-color-swatch {
	--mochi-swatch-color: #cccccc;
	width: 32px; height: 32px; padding: 0; border-radius: 50%; position: relative;
	background: var(--mochi-swatch-color);
	border: 2px solid var(--color-surface); /* separates the swatch color from the ring below */
	box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18); /* the neutral ring itself — visible on light or dark backgrounds */
	cursor: pointer;
	transition: box-shadow var(--dur-fast) var(--ease-out);
}
.mochi-color-swatch.is-selected { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18), 0 0 0 3px var(--color-primary); }
.mochi-color-swatch.is-unavailable {
	cursor: not-allowed; opacity: 0.5;
}
/* The diagonal "unavailable" slash — an overlay on top of the real swatch color, not a
   replacement for it, so the color itself still reads (a client can see WHICH color is
   coming later, not just that something is missing). */
.mochi-color-swatch.is-unavailable::after {
	content: ""; position: absolute; inset: -2px; border-radius: 50%;
	background: linear-gradient(
		to top right,
		transparent calc(50% - 1.5px),
		rgba(20, 20, 20, 0.75) calc(50% - 1.5px),
		rgba(20, 20, 20, 0.75) calc(50% + 1.5px),
		transparent calc(50% + 1.5px)
	);
}

.woocommerce div.product .quantity input.qty { width: 64px; height: 44px; border: 1px solid var(--color-border); text-align: center; font-family: var(--font-body); }
.woocommerce div.product .single_add_to_cart_button,
.woocommerce div.product .single_add_to_cart_button.wp-element-button,
.woocommerce div.product a.single_add_to_cart_button {
	background: var(--color-primary) !important; color: #fff !important; border: 0 !important; border-radius: var(--radius-base) !important;
	padding: 13px 20px !important; font-family: var(--font-body) !important; font-size: 13px !important; text-transform: uppercase;
	letter-spacing: 3.9px; font-weight: 700; cursor: pointer; width: 100%; margin-top: 12px;
}
.woocommerce div.product .single_add_to_cart_button:hover { background: var(--color-accent) !important; }
.woocommerce div.product .single_add_to_cart_button.disabled { opacity: 0.5; cursor: not-allowed; }

/* Finalization Stage 1: Buy Now — sits right after the add-to-cart form (rendered via
   woocommerce_after_add_to_cart_form, functions.php), so full-width + the same
   top-margin rhythm as the button it follows. .is-loading is the shared busy-state for
   both this and the real Add to Cart button while their AJAX request is in flight
   (main.js) — same visual language as everything else mid-request, not a spinner. */
.mochi-buy-now { width: 100%; margin-top: 12px; }
.single_add_to_cart_button.is-loading, .mochi-buy-now.is-loading { opacity: 0.6; pointer-events: none; }

/* Care Instructions / Ask a Question — measured from the reference (full-width bordered
   rows directly below Add to Cart, uppercase label + chevron, letter-spacing 3.84px,
   Outfit 12.8px). Native <details>/<summary>, no JS. */
.mochi-accordions { margin-top: calc(var(--space) * 3); border-top: 1px solid var(--color-border-subtle); }
.mochi-accordion { border-bottom: 1px solid var(--color-border-subtle); }
.mochi-accordion summary {
	display: flex; align-items: center; justify-content: space-between;
	padding: 15px 0; cursor: pointer; list-style: none;
	font-family: var(--font-body); font-size: 12.8px; font-weight: 400;
	text-transform: uppercase; letter-spacing: 3.84px; color: var(--color-text-primary);
}
.mochi-accordion summary::-webkit-details-marker { display: none; }
.mochi-accordion summary::after {
	content: "+"; font-size: 16px; font-weight: 300; transition: transform var(--dur-fast) var(--ease-out);
}
.mochi-accordion[open] summary::after { transform: rotate(45deg); }
.mochi-accordion-body { padding: 0 0 20px; color: var(--color-text-muted); font-size: 14px; line-height: 1.6; }
.mochi-accordion-body p { margin: 0; }

/* "Ask a Question" form — matches the reference's field set (Name/Email/Phone/Message),
   styled to the same input language as the rest of the site (quantity input, size
   swatches: 1px border, no radius, Outfit body font). */
.mochi-ask-question-form { margin-top: 4px; }
.mochi-form-row { margin: 0 0 14px; }
.mochi-form-row label {
	display: block; font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em;
	margin-bottom: 6px; color: var(--color-text-muted);
}
.mochi-form-row input, .mochi-form-row textarea {
	width: 100%; border: 1px solid var(--color-border); padding: 10px 12px;
	font-family: var(--font-body); font-size: 14px; color: var(--color-text-primary);
	background: var(--color-surface-raised);
}
.mochi-ask-question-form .btn { margin-top: 4px; }
.mochi-form-status { margin: 10px 0 0; font-size: 13px; min-height: 1.2em; }
.mochi-form-status.is-success { color: var(--color-primary); }
.mochi-form-status.is-error { color: var(--color-danger); }

.woocommerce-tabs { margin-top: calc(var(--space) * 6); border-top: 1px solid var(--color-border-subtle); }
.woocommerce-tabs ul.tabs { list-style: none; display: flex; gap: 24px; padding: 0; margin: 20px 0; }
.woocommerce-tabs ul.tabs li a { font-size: 13px; text-transform: uppercase; letter-spacing: 0.04em; }

/* ---------- WooCommerce: cart / checkout ---------- */

.woocommerce-cart table.cart, .woocommerce-checkout table.cart { width: 100%; border-collapse: collapse; }
.woocommerce-cart table.cart th, .woocommerce-cart table.cart td { padding: 16px 8px; border-bottom: 1px solid var(--color-border-subtle); text-align: left; }
.woocommerce-cart table.cart img { width: 72px; aspect-ratio: 3/4; object-fit: cover; }
.woocommerce-checkout-review-order-table { width: 100%; }
#place_order, .checkout-button {
	background: var(--color-primary); color: #fff; border: 0; padding: 13px 20px;
	text-transform: uppercase; letter-spacing: 3.9px; font-weight: 700; font-family: var(--font-body);
	font-size: 13px; cursor: pointer; width: 100%; border-radius: var(--radius-base);
}

/* ---------- Mini-cart (drawer contents) ---------- */

.widget_shopping_cart_content ul.woocommerce-mini-cart,
.widget_shopping_cart_content ul.wc-block-mini-cart-items { list-style: none; margin: 0; padding: 0; }
/* Task 1 (2026-08-29), visual polish pass #2 — root layout rework, presentation only:
   WooCommerce's mini-cart <li> contains `<a class="remove">`, then one `<a>` wrapping
   BOTH the <img> and the product name text as siblings (not independently wrappable
   without a template override), then our quantity/price <span> as a further sibling.
   As a plain flex row this put the name and the qty/price control side by side,
   fighting for width and wrapping awkwardly (human-flagged: title/image/size/price/
   remove alignment weak). Fixed with flex-wrap: the name-link is forced to its own
   full-width row (so image+name always sit cleanly together), and the quantity/price
   control that follows wraps to a second row, indented to sit under the TEXT rather
   than the image — a clean two-line card without touching the underlying markup. */
.widget_shopping_cart_content ul.woocommerce-mini-cart li {
	/* Right padding is just clearance for the absolutely-positioned remove ×
	   (below) — the drawer's own horizontal gutter now comes from .cart-drawer-body
	   (above), not stacked again here, so the × still lands inside that same gutter
	   via `right: 0` rather than sitting extra-far from the edge. */
	display: flex; flex-wrap: wrap; align-items: flex-start;
	padding: 18px 20px 18px 0; border-bottom: 1px solid var(--color-border-subtle);
	position: relative;
}
.widget_shopping_cart_content ul.woocommerce-mini-cart img,
.widget_shopping_cart_content .woocommerce-mini-cart-item img {
	width: 60px !important;
	height: 80px !important;
	aspect-ratio: 3/4;
	object-fit: cover;
	flex-shrink: 0;
	border-radius: var(--radius-base);
}
.widget_shopping_cart_content ul.woocommerce-mini-cart li > a:not(.remove) {
	display: flex; align-items: flex-start; gap: 14px; width: 100%; margin-bottom: 10px;
	font-family: var(--font-display); font-size: 13px; letter-spacing: 0.02em;
	color: var(--color-text-primary); line-height: 1.4;
}
.widget_shopping_cart_content .mochi-mini-cart-qty { margin-left: calc(60px + 14px); }
.widget_shopping_cart_content .remove {
	position: absolute; top: 18px; right: 0; font-size: 18px; font-weight: 300;
	color: var(--color-text-muted); line-height: 1;
}
.widget_shopping_cart_content .remove:hover { color: var(--color-danger); }
.widget_shopping_cart_content .woocommerce-mini-cart__total {
	display: flex; justify-content: space-between; align-items: baseline;
	padding: 18px 0; font-family: var(--font-display); font-size: 15px; font-weight: 400;
}
.widget_shopping_cart_content .woocommerce-mini-cart__buttons a {
	display: block; text-align: center; padding: 13px; margin-bottom: 10px;
	border: 1px solid var(--color-primary); border-radius: var(--radius-base);
	font-size: 12px; letter-spacing: 0.15em; text-transform: uppercase;
}
.widget_shopping_cart_content .woocommerce-mini-cart__buttons a.checkout { background: var(--color-primary); color: #fff; }
.widget_shopping_cart_content .woocommerce-mini-cart__empty-message { color: var(--color-text-muted); }

/* ---------- Responsive (moved here 2026-08-27 — real bug, human-flagged from an actual
   phone) ----------
   Real bug, not a rendering-tool illusion this time: human tested the live site on their
   own phone (LAN IP, `resize_window` is confirmed non-functional in this dev environment
   — see FLIGHT_RECORDER.md) and reported the PDP still needing horizontal
   resize/scrolling, and the gallery image showing "choti choti [tiny], on the side"
   instead of full-width. Root cause: this block used to sit ABOVE the desktop
   single-product/gallery rules (`main.css` §WooCommerce: single product). Neither side
   has higher CSS specificity, so on a narrow viewport BOTH the media query (true) and the
   unconditional desktop rule applied to the same selectors — and plain source order
   decided the tie. Because the desktop rules were declared LATER in the file, they always
   won, even inside the media query: `.single-product div.product` stayed a 2-column grid
   (each column squeezed to ~half a phone-width, forcing horizontal scroll), and
   `.woocommerce-product-gallery .flex-control-thumbs` stayed the desktop's absolute-
   positioned 80px-wide rail with `padding-left:92px` still reserving that space — exactly
   the "tiny images down the side" the human described. Moving this whole block to the
   true end of the file (this position) fixes it structurally: mobile overrides now always
   come last, so they win the cascade against everything above regardless of selector
   specificity, the same fix already applied ad-hoc with individual !important flags
   elsewhere in this file for the identical class of bug (see `.variations select`,
   `.flex-control-thumbs li` comments above) — this is that same fix applied at the
   section level instead of rule-by-rule. Still not confirmed by an actual rendered
   screenshot in this environment (see FLIGHT_RECORDER.md) — verified by static CSS/
   cascade analysis plus the human's own real-device report, not by re-rendering here. */

@media (max-width: 1024px) {
	.product-grid, ul.products { grid-template-columns: repeat(2, 1fr); }
	.footer-grid { grid-template-columns: 1fr 1fr; }
	.single-product div.product { grid-template-columns: 1fr; }
	.single-product div.product > .woocommerce-product-gallery { grid-column: 1; grid-row: 1; }
	.single-product div.product > .summary.entry-summary { grid-column: 1; grid-row: 2; margin-top: calc(var(--space) * 4); }
}

@media (max-width: 640px) {
	.header-row { grid-template-columns: auto 1fr auto; }
	.site-branding { text-align: left; grid-column: 1; }
	.header-actions { grid-column: 3; }
	.primary-nav { display: none; }
	.mobile-nav-toggle { display: inline-flex; grid-column: 2; justify-self: end; }
	.hero { min-height: 480px; }
	.footer-grid { grid-template-columns: 1fr; gap: calc(var(--space) * 4); }
	/* Vertical thumbnail rail beside the image (desktop pattern) doesn't fit a narrow
	   viewport — drop to a horizontal strip below the main image, the standard mobile PDP
	   gallery pattern. */
	.woocommerce-product-gallery { padding-left: 0; }
	.woocommerce-product-gallery .flex-control-thumbs {
		position: static; width: auto; margin-top: 12px;
		flex-direction: row; flex-wrap: wrap;
	}
	.flex-control-thumbs li { width: 64px !important; float: none !important; }
}
