/* =========================================================================
 * Quick add sheet.
 *
 * LIGHT ONLY. The shop has no dark mode and never has; the first version of
 * this file was built dark to match the phone app, which was simply the wrong
 * reference -- the app has a dark theme, the website does not, and a dark sheet
 * sliding up over a white shop looks like a different site.
 *
 * EVERY RULE IS SCOPED THROUGH .sqa-sheet OR .sqa-btn, AND THAT IS NOT STYLE
 * PREFERENCE. Woodmart styles every <button> on the site globally, at a
 * specificity a single class cannot beat -- the product gallery arrows lost
 * `position` itself once and fell into normal flow as purple blocks. Anything
 * here that is a bare element selector will be overridden, or will leak.
 * ========================================================================= */

/*
 * BUTTONS TAKE THE THEME'S OWN ACCENT, THROUGH THE THEME'S OWN VARIABLE.
 *
 * `--wd-alternative-color` is what Woodmart's accented buttons are painted
 * with (`background-color:var(--wd-alternative-color)` in style.min.css) --
 * View cart, Checkout, the cart drawer's quantity steppers. Reading the
 * variable rather than copying the value out of it means a colour change in
 * wp-admin reaches this sheet too, instead of leaving one purple button behind
 * that nobody remembers is hard-coded here.
 *
 * The fallback is the value the shop has today, for the moment before the
 * theme's inline CSS is parsed.
 */
:root {
	--sqa-btn: var(--wd-alternative-color, rgba(74, 0, 81, .83));
	--sqa-pink: #db7093;
	--sqa-ink: #241c2b;
	--sqa-muted: #8a7e8c;
	--sqa-tint: #f4f1f6;
	--sqa-pale: #fbe9f0;
	--sqa-line: rgba(36, 28, 43, .10);
}

/* ── the button on the card ─────────────────────────────────────────── */

.sqa-btn {
	--sqa-bag: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z'/%3E%3Cpath d='M3 6h18'/%3E%3Cpath d='M16 10a4 4 0 0 1-8 0'/%3E%3C/svg%3E");
}

.sqa-btn .sqa-icon::before {
	content: "";
	display: block;
	width: 1em;
	height: 1em;
	margin: 0 auto;
	background-color: currentColor;
	-webkit-mask: var(--sqa-bag) center / contain no-repeat;
	mask: var(--sqa-bag) center / contain no-repeat;
}

/* Woodmart's add-to-cart button in the loop is emptied server-side while quick
   add is on -- the sheet does that job, and better, because it lets her pick a
   size first. The wrapper div is printed by the theme's template whether or not
   anything went inside it, so an empty one must be taken out of the layout or
   it leaves a second, dead circle above the real button. */
.wd-buttons .wd-add-btn:empty {
	display: none;
}

/* ── the sheet ──────────────────────────────────────────────────────── */

.sqa-sheet {
	position: fixed;
	inset: 0;
	z-index: 100000;
	display: flex;
	align-items: flex-end;
	justify-content: center;
	visibility: hidden;
	opacity: 0;
	transition: opacity .22s ease, visibility 0s linear .22s;
}

.sqa-sheet.is-open {
	visibility: visible;
	opacity: 1;
	transition: opacity .22s ease;
}

.sqa-sheet .sqa-scrim {
	position: absolute;
	inset: 0;
	background: rgba(36, 28, 43, .45);
	border: 0;
	padding: 0;
	margin: 0;
	width: 100%;
	cursor: pointer;
}

.sqa-sheet .sqa-panel {
	position: relative;
	width: 100%;
	max-width: 560px;
	max-height: 92vh;
	display: flex;
	flex-direction: column;
	background: #fff;
	color: var(--sqa-ink);
	border-radius: 22px 22px 0 0;
	box-shadow: 0 -8px 40px rgba(36, 28, 43, .22);
	transform: translateY(14px);
	transition: transform .26s cubic-bezier(.22, .9, .3, 1);
	overflow: hidden;
}

.sqa-sheet.is-open .sqa-panel {
	transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
	.sqa-sheet,
	.sqa-sheet .sqa-panel {
		transition: none;
	}
}

/* ── header ─────────────────────────────────────────────────────────── */

.sqa-sheet .sqa-head {
	display: flex;
	align-items: flex-start;
	gap: 14px;
	padding: 20px 20px 16px;
	border-bottom: 1px solid var(--sqa-line);
}

.sqa-sheet .sqa-thumb {
	flex: 0 0 auto;
	width: 68px;
	height: 68px;
	border-radius: 12px;
	object-fit: cover;
	background: var(--sqa-tint);
}

.sqa-sheet .sqa-titles {
	flex: 1 1 auto;
	min-width: 0;
}

.sqa-sheet .sqa-name {
	margin: 0 0 6px;
	font-size: 15px;
	font-weight: 700;
	line-height: 1.3;
	color: var(--sqa-ink);
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
}

.sqa-sheet .sqa-price {
	font-size: 19px;
	font-weight: 700;
	color: var(--sqa-pink);
	line-height: 1.2;
}

/* WooCommerce writes the old price as <del> and the new as <ins> inside
   get_price_html(), so both arrive already marked up. */
.sqa-sheet .sqa-price del {
	font-size: 14px;
	font-weight: 400;
	color: var(--sqa-muted);
	margin-inline-start: 6px;
}

.sqa-sheet .sqa-price ins {
	text-decoration: none;
	background: none;
	color: var(--sqa-pink);
}

.sqa-sheet .sqa-close {
	flex: 0 0 auto;
	width: 36px;
	height: 36px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: var(--sqa-tint);
	color: var(--sqa-ink);
	font-size: 19px;
	line-height: 36px;
	text-align: center;
	cursor: pointer;
}

.sqa-sheet .sqa-close:focus-visible {
	background: var(--sqa-pale);
}

@media (hover: hover) {
	.sqa-sheet .sqa-close:hover {
		background: var(--sqa-pale);
	}
}

/* ── the choices ────────────────────────────────────────────────────── */

.sqa-sheet .sqa-body {
	flex: 1 1 auto;
	overflow-y: auto;
	padding: 18px 20px 4px;
	-webkit-overflow-scrolling: touch;
}

.sqa-sheet .sqa-body:empty {
	padding: 0;
}

.sqa-sheet .sqa-group {
	margin-bottom: 18px;
}

.sqa-sheet .sqa-label {
	display: block;
	margin-bottom: 9px;
	font-size: 13px;
	font-weight: 600;
	color: var(--sqa-muted);
}

.sqa-sheet .sqa-pills {
	display: flex;
	flex-wrap: wrap;
	gap: 9px;
}

.sqa-sheet .sqa-pill {
	padding: 11px 17px;
	border: 1px solid var(--sqa-line);
	border-radius: 11px;
	background: #fff;
	color: var(--sqa-ink);
	font-size: 14px;
	font-weight: 500;
	line-height: 1.2;
	cursor: pointer;
	transition: background .15s ease, border-color .15s ease, color .15s ease;
}

/*
 * HOVER MUST NEVER OUTRANK THE CHOSEN PILL, AND IT DID.
 *
 * `.sqa-pill:hover:not(.is-off)` counts FOUR classes -- two classes, the
 * :hover, and the .is-off inside :not() -- against three for
 * `.sqa-pill.is-on`. So hover won, and repainted the selected pill with the
 * pale background. On a phone that is not a passing state: a tap leaves the
 * hover stuck, so the size she just chose sat there looking unchosen, and
 * whether it came out purple or pale depended on where she had last tapped.
 *
 * Excluding .is-on fixes the ranking. The (hover: hover) query is the belt to
 * that brace -- a touch screen has no real hover and should never apply one.
 */
@media (hover: hover) {
	.sqa-sheet .sqa-pill:hover:not(.is-off):not(.is-on) {
		background: var(--sqa-tint);
		border-color: var(--sqa-btn);
	}
}

.sqa-sheet .sqa-pill.is-on {
	background: var(--sqa-btn);
	border-color: var(--sqa-btn);
	color: #fff;
	font-weight: 600;
}

/* ── colour swatches ────────────────────────────────────────────────
   Shown rather than named, the way the single product page shows them. The
   name is not lost: it goes in the group label ("Color: Dusty Blue"), on the
   title attribute, and on aria-label, so a swatch is never an unlabelled
   colour a screen reader cannot announce. */

.sqa-sheet .sqa-swatches {
	gap: 11px;
}

.sqa-sheet .sqa-pill.sqa-swatch {
	position: relative;
	width: 58px;
	height: 58px;
	padding: 3px;
	border-radius: 50%;
	overflow: visible;
}

.sqa-sheet .sqa-swatch-bg {
	display: block;
	position: relative;
	width: 100%;
	height: 100%;
	border-radius: 50%;
	background-color: var(--sqa-tint);
	box-shadow: inset 0 0 0 1px rgba(36, 28, 43, .12);
	overflow: hidden;
}

/*
 * THE PHOTOGRAPH FADES OVER THE FLAT COLOUR, IT DOES NOT REPLACE IT.
 *
 * The colour ships with the card and is correct immediately; the photograph
 * arrives with the variations, a few hundred milliseconds later even when the
 * request was started on pointerdown. Swapping a background-image at that
 * moment is a jump, and a jump is what reads as broken -- the wait itself
 * never did. A background-image cannot be transitioned, so the photo goes on
 * its own layer and that layer's opacity is what moves.
 */
.sqa-sheet .sqa-swatch-bg::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 50%;
	background-image: var(--shot, none);
	background-size: cover;
	background-position: center;
	opacity: 0;
	transition: opacity .2s ease;
}

.sqa-sheet .sqa-swatch-bg.has-shot::after {
	opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
	.sqa-sheet .sqa-swatch-bg::after {
		transition: none;
	}
}

/* The ring is on the swatch, the colour is on the child -- so a selected
   swatch reads as selected without the purple covering the colour itself,
   which is the whole thing she is trying to look at. */
.sqa-sheet .sqa-pill.sqa-swatch.is-on {
	background: transparent;
	border-color: var(--sqa-btn);
	box-shadow: 0 0 0 1px var(--sqa-btn);
}

.sqa-sheet .sqa-pill.sqa-swatch.is-off {
	text-decoration: none;
	opacity: .35;
}

/* A struck-through swatch is meaningless, so a sold-out colour gets a slash
   drawn across it instead. */
.sqa-sheet .sqa-pill.sqa-swatch.is-off::after {
	content: "";
	position: absolute;
	inset: 3px;
	border-radius: 50%;
	background: linear-gradient(
		to bottom right,
		transparent calc(50% - 1px),
		rgba(36, 28, 43, .55) calc(50% - 1px),
		rgba(36, 28, 43, .55) calc(50% + 1px),
		transparent calc(50% + 1px)
	);
}

/* Sold out, not hidden. A size that exists and is gone is information; a size
   that vanishes reads as a size never made, and she goes looking for it. */
.sqa-sheet .sqa-pill.is-off {
	color: #bdb5c1;
	background: var(--sqa-tint);
	border-color: transparent;
	text-decoration: line-through;
	cursor: not-allowed;
}

/* ── quantity ───────────────────────────────────────────────────────── */

.sqa-sheet .sqa-qty-row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 14px;
	padding: 0 20px;
	margin-bottom: 14px;
}

.sqa-sheet .sqa-qty-row .sqa-label {
	margin-bottom: 0;
}

.sqa-sheet .sqa-stepper {
	display: flex;
	align-items: center;
	border: 1px solid var(--sqa-line);
	border-radius: 11px;
	overflow: hidden;
}

.sqa-sheet .sqa-step {
	width: 42px;
	height: 42px;
	padding: 0;
	border: 0;
	background: #fff;
	color: var(--sqa-ink);
	font-size: 19px;
	line-height: 42px;
	cursor: pointer;
}

.sqa-sheet .sqa-step:disabled {
	color: #cfc8d3;
	cursor: not-allowed;
}

/*
 * WRAPPED FOR THE SAME REASON THE PILL HOVER IS. A phone has no hover, but it
 * applies one on tap and leaves it there, so the last + or - pressed stayed
 * tinted while the other stayed white -- two buttons of a matched pair sitting
 * in different colours until something else was touched.
 */
@media (hover: hover) {
	.sqa-sheet .sqa-step:not(:disabled):hover {
		background: var(--sqa-tint);
	}
}

.sqa-sheet .sqa-qty {
	min-width: 40px;
	text-align: center;
	font-size: 15px;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
}

/* ── stock and errors ───────────────────────────────────────────────── */

.sqa-sheet .sqa-note {
	margin: 0 0 14px;
	padding: 0 20px;
	font-size: 13px;
	font-weight: 600;
	color: #c2670f;
}

.sqa-sheet .sqa-note:empty {
	display: none;
}

.sqa-sheet .sqa-note.is-error {
	color: #c0392b;
}

/* ── the button ─────────────────────────────────────────────────────── */

.sqa-sheet .sqa-foot {
	padding: 4px 20px calc(20px + env(safe-area-inset-bottom));
	background: #fff;
	border-top: 1px solid var(--sqa-line);
	padding-top: 14px;
}

.sqa-sheet .sqa-add {
	display: block;
	width: 100%;
	padding: 16px 20px;
	border: 0;
	border-radius: 14px;
	background: var(--sqa-btn);
	color: #fff;
	font-size: 15px;
	font-weight: 700;
	letter-spacing: .04em;
	text-transform: uppercase;
	cursor: pointer;
	transition: opacity .15s ease, background .15s ease;
}

@media (hover: hover) {
	.sqa-sheet .sqa-add:hover:not(:disabled) {
		opacity: .9;
	}
}

.sqa-sheet .sqa-add:disabled {
	background: var(--sqa-tint);
	color: #b5adba;
	cursor: not-allowed;
}

.sqa-sheet .sqa-add.is-done {
	background: #3f8f68;
	color: #fff;
}

/* ── loading ────────────────────────────────────────────────────────── */

/*
 * NOTHING FADES IN. The sizes used to be drawn at 45% opacity until the
 * variations arrived and then jump to full -- which read as the panel
 * correcting itself every single time it opened, for a request that takes a
 * few hundred milliseconds.
 *
 * They are drawn final and tappable straight away instead. A choice made
 * before the data lands is still safe: `paint()` greys out anything that
 * turns out to be unavailable and clears the selection if it was one of them,
 * and the Add button stays disabled until a real variation resolves, so
 * nothing can be added on the strength of a size we have not confirmed.
 */

/* ── the page behind must not scroll while the sheet is up ──────────── */

body.sqa-locked {
	overflow: hidden;
}

/* ── colour dots on the product card ────────────────────────────────
   Flat colour only. The dots render with the page, so a photograph on each
   would mean three to five extra downloads per card before anyone has touched
   anything. The photograph is fetched only when a dot is tapped. */

.sgs {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	/* The gap tightens with the dots. At 7 colours: 7x15 + 6x5 = 135px, inside
	   the ~132-145px a card has on a 360px phone at 2 columns. */
	gap: clamp(4px, calc(var(--sgs-size, 20px) * .35), 7px);
	margin: 10px 0 4px;
}

/*
 * THE DOTS CAME OUT AS OVALS, AND IT IS THE GLOBAL BUTTON TRAP AGAIN.
 *
 * Woodmart sizes buttons from `--wd-form-height: 42px` and its own padding, so
 * `width: 22px; height: 22px` gave a 22-wide, ~31-tall pill: the width held and
 * the height did not. Rather than hunt the exact rule through 578 KB of
 * minified CSS, the dot is pinned from every direction at once -- min and max
 * on both axes, aspect-ratio as a backstop, border-box so the ring cannot add
 * to it, and a zero line-height so no inherited leading creeps in.
 *
 * `flex: 0 0 <size>` rather than `auto`: in a narrow card the row would
 * otherwise shrink the dots unevenly, which is the same bug wearing a
 * different hat.
 */
.sgs .sgs-dot {
	/* Overridden per product from the dot count; this is the default. */
	--sgs-size: 20px;
	box-sizing: border-box;
	flex: 0 0 var(--sgs-size);
	width: var(--sgs-size);
	min-width: var(--sgs-size);
	max-width: var(--sgs-size);
	height: var(--sgs-size);
	min-height: var(--sgs-size);
	max-height: var(--sgs-size);
	aspect-ratio: 1 / 1;
	padding: 0;
	margin: 0;
	border: 0;
	border-radius: 50%;
	background: none;
	cursor: pointer;
	line-height: 0;
	font-size: 0;
	position: relative;
	-webkit-appearance: none;
	appearance: none;
}

/*
 * A BIGGER TARGET THAN THE DOT, WITHOUT A BIGGER DOT.
 *
 * A 20px circle is a small thing to hit with a thumb, and growing it costs
 * room the card does not have. This extends the tappable area past the visible
 * dot without taking a single pixel of layout, so seven colours still fit on
 * one line while each stays comfortably tappable.
 */
.sgs .sgs-dot::after {
	content: "";
	position: absolute;
	/* Grows as the dot shrinks, so every dot keeps a ~32px reach whatever its
	   drawn size. Costs no layout: it is positioned, not in flow. */
	inset: calc((var(--sgs-size, 20px) - 32px) / 2);
	border-radius: 50%;
}

.sgs .sgs-bg {
	display: block;
	width: 100%;
	height: 100%;
	border-radius: 50%;
	background-color: var(--sgs-c, #eee);
	/* A white or cream swatch needs an edge or it is an invisible hole. */
	box-shadow: inset 0 0 0 1px rgba(36, 28, 43, .18);
}

/* The ring goes around the dot, never over it -- the colour is the thing she
   is looking at. Same rule as the swatches inside the sheet. */
/* The ring sits OUTSIDE the colour rather than around it as a border, so the
   dot itself never shrinks when chosen -- a border would eat into the 20px. */
.sgs .sgs-dot.is-on .sgs-bg {
	box-shadow: inset 0 0 0 1px rgba(36, 28, 43, .18),
		0 0 0 2px #fff,
		0 0 0 4px var(--sqa-btn, rgba(74, 0, 81, .83));
}

@media (hover: hover) {
	.sgs .sgs-dot:hover:not(.is-on) .sgs-bg {
		box-shadow: inset 0 0 0 1px rgba(36, 28, 43, .18),
			0 0 0 2px #fff,
			0 0 0 4px rgba(36, 28, 43, .25);
	}
}

.sgs .sgs-more {
	font-size: 11px;
	font-weight: 600;
	color: var(--sqa-muted, #8a7e8c);
	line-height: 1;
}

/* Once a colour is chosen the hover photograph must stop replacing it. On a
   phone the hover sticks, so this is not a passing problem. */
.wd-product.sgs-has-choice .wd-product-img-hover,
.wd-product.sgs-has-choice .hover-img {
	display: none !important;
}
