/**
 * Painting room demo.
 *
 * The whole scene is driven by one number: --stpd-ppc, the pixels-per-cm that
 * JS recomputes whenever the scene is resized. Every dimension below is
 * `<real cm> * var(--cm)`, which is why a 200cm sofa always renders exactly
 * twice as wide as a 100cm painting.
 */

.stpd {
	--stpd-radius: 14px;
	--stpd-gap: 20px;
	/* Every colour below is overridable from Settings -> Painting Demo, which
	   sets these same custom properties inline on this element. The values
	   here are the fallbacks for anything the admin has not touched. */
	--stpd-ink: #1c1c1e;
	--stpd-muted: #6b6b70;
	--stpd-line: #e3e1dd;
	--stpd-surface: #fff;
	--stpd-surface-2: #f6f5f3;
	--stpd-accent: #1c1c1e;
	--stpd-accent-text: #fff;
	--stpd-toggle-off: #d5d3ce;
	--stpd-toggle-knob: #fff;
	--stpd-baseboard-color: #fafaf8;
	--stpd-figure-color: #1c1c1e;
	--stpd-label-bg: #2a2a2e;
	--stpd-label-ink: #fff;
	--stpd-rule-color: #7a7a7e;
	--stpd-rule-label-bg: #fff;
	--stpd-rule-label-ink: #1c1c1e;

	/* The chosen thickness, and the width actually in play. Keeping them
	   apart means the rulers and the shadow can read one number that is
	   simply 0 while the frame is switched off. */
	--stpd-frame-t: 4;
	--stpd-frame-w: 0;

	display: grid;
	gap: var(--stpd-gap);
	container-type: inline-size;
	color: var(--stpd-ink);
	font-family: inherit;
	/* Left to itself the demo fills a full-width page section and swamps it,
	   so it takes a maximum width and centres in whatever space it is given. */
	max-width: min(100%, var(--stpd-max-w, 880px));
	margin-inline: auto;
}

.stpd--framed {
	--stpd-frame-w: var(--stpd-frame-t);
}

/* Themes and page builders style every button on the page. Neutralising that
   here - and giving the components below a higher specificity - keeps their
   look from leaking in. */
.stpd button {
	appearance: none;
	-webkit-appearance: none;
	margin: 0;
	border: 0;
	background: none;
	font: inherit;
	color: inherit;
	text-transform: none;
	letter-spacing: normal;
	box-shadow: none;
	min-height: 0;
}

.stpd *,
.stpd *::before,
.stpd *::after {
	box-sizing: border-box;
}

.stpd .screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	white-space: nowrap;
}

/* ------------------------------------------------------------------ */
/* Scene                                                               */
/* ------------------------------------------------------------------ */

.stpd__stage {
	position: relative;
	border-radius: var(--stpd-radius);
	overflow: hidden;
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 12px 32px rgba(0, 0, 0, 0.08);
}

/* ------------------------------------------------------------------ */
/* Previous / next arrows                                              */
/* ------------------------------------------------------------------ */

/* They sit on the stage rather than inside the scene, so the scene's own
   overflow and stacking context stay purely about the room. */
.stpd .stpd__nav {
	position: absolute;
	top: 50%;
	z-index: 9;
	display: grid;
	place-items: center;
	width: 44px;
	height: 44px;
	padding: 0;
	border-radius: 50%;
	background: var(--stpd-nav-bg, var(--stpd-surface));
	color: var(--stpd-nav-icon, var(--stpd-ink));
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.14), 0 6px 16px rgba(0, 0, 0, 0.18);
	cursor: pointer;
	transform: translateY(-50%);
	transition: opacity 0.15s ease, transform 0.15s ease;
	opacity: 0.9;
}

/*
 * Only on devices with a real pointer. A tap leaves :hover stuck on the
 * button until something else is tapped, which is what kept the arrows
 * looking held-down after a click.
 */
@media (hover: hover) {
	.stpd .stpd__nav:hover {
		background: var(--stpd-nav-hover-bg, var(--stpd-nav-bg, var(--stpd-surface)));
		color: var(--stpd-nav-hover-icon, var(--stpd-nav-icon, var(--stpd-ink)));
		opacity: 1;
	}
}

.stpd .stpd__nav:focus-visible {
	opacity: 1;
}

/*
 * A click leaves the arrow focused. Keyboard focus should still show, but
 * pointer focus must not keep the arrow in its active look once the pointer
 * has moved on - nor let a theme's own :focus styling show through.
 */
.stpd .stpd__nav:focus:not(:focus-visible):not(:hover),
.stpd .stpd__nav:not(:hover):not(:focus-visible) {
	background: var(--stpd-nav-bg, var(--stpd-surface));
	color: var(--stpd-nav-icon, var(--stpd-ink));
	opacity: 0.9;
	transform: translateY(-50%);
}

.stpd .stpd__nav:focus-visible {
	outline: 2px solid var(--stpd-focus, var(--stpd-accent));
	outline-offset: 2px;
}

.stpd .stpd__nav--prev {
	left: 14px;
}

.stpd .stpd__nav--next {
	right: 14px;
}

@media (hover: hover) {
	.stpd .stpd__nav:hover.stpd__nav--prev {
		transform: translate(-2px, -50%);
	}

	.stpd .stpd__nav:hover.stpd__nav--next {
		transform: translate(2px, -50%);
	}
}

.stpd .stpd__nav svg {
	width: 20px;
	height: 20px;
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* The wall-height rule runs down the left edge at 14px, which is exactly
   where the previous arrow lands; nudging both arrows in keeps them clear
   of it while the measurements are showing. */
.stpd--rulers .stpd__nav--prev {
	left: 46px;
}

.stpd__scene {
	/* Which slice of wall is on show. The container query near the bottom of
	   this file swaps in the narrow one; doing it here rather than from JS is
	   what keeps the scene's height stable from the very first paint. */
	--stpd-wall-w: var(--stpd-wall-w-wide, 400);

	/* --stpd-ppc is set by JS; the fallback keeps the scene sane if JS never runs. */
	--stpd-ppc: 1;
	--cm: calc(var(--stpd-ppc) * 1px);

	/* Distance from the bottom of the scene to the bottom edge of the painting. */
	--stpd-p-bottom: calc((var(--stpd-floor-d) + var(--stpd-hang) - var(--stpd-p-h) / 2) * var(--cm));

	position: relative;
	width: 100%;
	aspect-ratio: var(--stpd-wall-w) / calc(var(--stpd-wall-h) + var(--stpd-floor-d));
	overflow: hidden;
	background: var(--stpd-wall-color);
	isolation: isolate;
}

.stpd__wall {
	position: absolute;
	inset: 0 0 calc(var(--stpd-floor-d) * var(--cm)) 0;
	background-color: var(--stpd-wall-color);
	/* A faint fall-off from the top left reads as ambient window light. */
	background-image: linear-gradient(160deg, rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0) 45%, rgba(0, 0, 0, 0.05));
	z-index: 1;
}

.stpd__floor {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: calc(var(--stpd-floor-d) * var(--cm));
	background-repeat: repeat;
	background-position: left top;
	z-index: 1;
}

/* Textures carry a real tile width, so the planks scale with everything else. */
.stpd__floor.is-textured {
	background-size: calc(var(--stpd-tile) * var(--cm)) auto;
}

.stpd__floor::after {
	/* Sheen: brighter where the floor meets the wall, darker toward the viewer. */
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(to bottom, rgba(255, 255, 255, 0.14), rgba(0, 0, 0, 0.1));
}

.stpd__baseboard {
	position: absolute;
	left: 0;
	right: 0;
	bottom: calc(var(--stpd-floor-d) * var(--cm));
	height: calc(var(--stpd-baseboard) * var(--cm));
	background: var(--stpd-baseboard-color);
	border-bottom: 1px solid rgba(0, 0, 0, 0.14);
	box-shadow: 0 -1px 0 rgba(0, 0, 0, 0.05);
	z-index: 2;
}

/* ------------------------------------------------------------------ */
/* Painting                                                            */
/* ------------------------------------------------------------------ */

.stpd__painting {
	position: absolute;
	left: 50%;
	bottom: var(--stpd-p-bottom);
	width: calc(var(--stpd-p-w) * var(--cm));
	height: calc(var(--stpd-p-h) * var(--cm));
	margin: 0;
	transform: translateX(-50%);
	z-index: 4;
	transition: width 0.28s ease, height 0.28s ease, bottom 0.28s ease;
}

/*
 * The double class, and the !important, are both deliberate.
 *
 * Nearly every theme ships `img { height: auto }` in some form, and where
 * that wins the artwork renders at its own proportions instead of the size
 * it is sold at - a picture a few percent taller than declared then hangs
 * below the frame's bottom rail, and, far worse, the whole scene quietly
 * misreports the size of the painting. The rendered box IS the measurement
 * here, so it is not something a theme may have an opinion about.
 */
/*
 * Size is a measurement; everything else here is decoration. The two are
 * split deliberately, because they want opposite things from a theme.
 *
 * Elementor ships `.elementor img { height:auto; box-shadow:none; ... }`, and
 * most themes ship something like it. Where that wins on height, an image a
 * few percent taller than its declared size renders taller than the box it
 * is sold at - it hangs past the frame, and the scene misreports how big the
 * painting is. So the dimensions are pinned hard enough that nothing can
 * have an opinion about them.
 */
.stpd .stpd__painting-img {
	display: block;
	width: 100% !important;
	height: 100% !important;
	max-width: none;
	max-height: none;
	min-width: 0;
	min-height: 0;
	/* The box is fixed to the declared size, so an image whose proportions
	   disagree is cropped rather than distorted or letterboxed - which is
	   also what keeps the frame flush to every edge of it. */
	object-fit: cover;
	object-position: center;
}

/*
 * The edge line and the shadow, on the other hand, are only a look, and they
 * stay at a specificity a theme can still beat - which is exactly what an
 * Elementor site does with its `box-shadow: none`. Pinning these too would
 * force a hairline bezel onto sites that had deliberately dropped it.
 */
.stpd__painting-img {
	background: #d8d4cd;
	box-shadow:
		0 0 0 1px rgba(0, 0, 0, 0.18),
		0 2px 4px rgba(0, 0, 0, 0.16),
		0 14px 28px rgba(0, 0, 0, 0.22);
	user-select: none;
}

/* The frame grows outward from the artwork rather than inward, so hanging a
   frame on a 100cm painting still leaves 100cm of painting - the measurements
   and the wall space it needs are the only honest things here, and a frame
   that ate into them would make both wrong. */
.stpd__painting-frame {
	position: absolute;
	inset: calc(var(--stpd-frame-w) * var(--cm) * -1);
	display: none;
	background: var(--stpd-frame-bg, #c9a227);
	box-shadow:
		0 0 0 1px rgba(0, 0, 0, 0.2),
		0 2px 4px rgba(0, 0, 0, 0.16),
		0 14px 28px rgba(0, 0, 0, 0.22);
	z-index: -1;
	transition: inset 0.2s ease;
}

.stpd--framed .stpd__painting-frame {
	display: block;
}

/* Framed, the frame carries the weight of the shadow and the picture keeps
   only the thin dark line where the rebate laps over the artwork. */
.stpd--framed .stpd__painting-img {
	box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
}

/* Contact shadow on the wall just under the bottom edge. */
.stpd__painting-shadow {
	position: absolute;
	left: 4%;
	right: 4%;
	/* Follows the bottom of the frame rather than the bottom of the canvas. */
	bottom: calc(-3% - var(--stpd-frame-w) * var(--cm));
	height: 6%;
	background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.28), rgba(0, 0, 0, 0) 70%);
	filter: blur(2px);
	z-index: -1;
}

/* ------------------------------------------------------------------ */
/* Props and the scale figure                                          */
/* ------------------------------------------------------------------ */

.stpd__props {
	position: absolute;
	inset: 0;
	z-index: 6;
	pointer-events: none;
}

/* Standing a prop at the wall/floor junction puts it at the very back edge of
   the floor, which reads as floating. Bringing it forward by --stpd-stand
   leaves floor visible in front of it, so it sits *on* something. */
.stpd__prop {
	position: absolute;
	bottom: calc((var(--stpd-floor-d) - var(--stpd-stand, 0)) * var(--cm));
	width: calc(var(--stpd-prop-w) * var(--cm));
	transition: opacity 0.22s ease;
	/* So the contact shadow below can sit behind the image without escaping
	   into the scene's own stacking order. */
	isolation: isolate;
}

.stpd__prop img {
	display: block;
	width: 100%;
	height: auto;
	user-select: none;
}

/* Shadows are the one part of the scene that is a guess rather than a
   measurement, so they can be switched off wholesale for cut-outs that
   already carry their own - or for a flatter, more catalogue-like look. */
.stpd--prop-shadows .stpd__prop img {
	filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.28));
}

/* A shadow pooling on the floor under the object. The prop's own drop-shadow
   traces its alpha, which does almost nothing for a sofa on thin legs. */
.stpd--prop-shadows .stpd__prop::after,
.stpd--prop-shadows .stpd__figure::after {
	--stpd-pool: max(6px, calc(var(--stpd-stand, 12) * var(--cm) * 0.8));

	content: "";
	position: absolute;
	left: -6%;
	right: -6%;
	height: var(--stpd-pool);
	/* Centred on the base line, so it pools around the feet rather than
	   climbing the wall behind the object. */
	bottom: calc(var(--stpd-pool) / -2);
	background: radial-gradient(ellipse at 50% 50%, rgba(0, 0, 0, 0.32), rgba(0, 0, 0, 0) 70%);
	z-index: -1;
	pointer-events: none;
}

.stpd__prop--left {
	left: calc(var(--stpd-prop-offset) * var(--cm));
}

.stpd__prop--right {
	right: calc(var(--stpd-prop-offset) * var(--cm));
}

.stpd__prop--center {
	left: 50%;
	transform: translateX(calc(-50% + var(--stpd-prop-offset) * var(--cm)));
}

.stpd__prop.is-hidden {
	display: none;
}

.stpd__figure {
	position: absolute;
	bottom: calc((var(--stpd-floor-d) - var(--stpd-stand, 0)) * var(--cm));
	height: calc(var(--stpd-fig-h) * var(--cm));
	z-index: 5;
	display: none;
	pointer-events: none;
}

.stpd--silhouette .stpd__figure {
	display: block;
}

.stpd__figure > svg,
.stpd__figure > img {
	display: block;
	height: 100%;
	width: auto;
}

/* The built-in figure is drawn from overlapping shapes, so the fill stays
   opaque and the whole element is faded instead - otherwise every overlap
   would show up as a darker seam. */
.stpd__figure > svg {
	fill: var(--stpd-figure-color);
	opacity: 0.3;
}

.stpd--prop-shadows .stpd__figure > img {
	filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.18));
}

.stpd__figure--left {
	left: calc(var(--stpd-fig-offset) * var(--cm));
}

.stpd__figure--right {
	right: calc(var(--stpd-fig-offset) * var(--cm));
}

.stpd__figure--center {
	left: 50%;
	transform: translateX(calc(-50% + var(--stpd-fig-offset) * var(--cm)));
}

.stpd__figure-label {
	position: absolute;
	top: -6px;
	left: 50%;
	transform: translate(-50%, -100%);
	font-size: 11px;
	line-height: 1;
	padding: 4px 7px;
	border-radius: 999px;
	background: var(--stpd-label-bg);
	color: var(--stpd-label-ink);
	white-space: nowrap;
}

/* ------------------------------------------------------------------ */
/* Measurement rules                                                   */
/* ------------------------------------------------------------------ */

/* Measurements sit above the props and the vignette: a guide that a sofa can
   hide is worse than no guide at all. */
.stpd__rulers {
	position: absolute;
	inset: 0;
	z-index: 8;
	display: none;
	pointer-events: none;
	--stpd-rule-ink: var(--stpd-rule-color);
}

.stpd--rulers .stpd__rulers {
	display: block;
}

.stpd__rule {
	position: absolute;
}

/* End ticks, drawn across the rule's axis. */
.stpd__rule::before,
.stpd__rule::after {
	content: "";
	position: absolute;
	background: var(--stpd-rule-ink);
}

.stpd__rule-label {
	position: absolute;
	font-size: 11px;
	line-height: 1;
	padding: 4px 7px;
	border-radius: 999px;
	background: var(--stpd-rule-label-bg);
	color: var(--stpd-rule-label-ink);
	white-space: nowrap;
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.16);
}

/* Wall height, down the left edge. */
.stpd__rule--wall {
	left: 14px;
	bottom: calc(var(--stpd-floor-d) * var(--cm));
	height: calc(var(--stpd-wall-h) * var(--cm));
	width: 1px;
	background: var(--stpd-rule-ink);
}

.stpd__rule--wall::before,
.stpd__rule--wall::after {
	left: -5px;
	width: 11px;
	height: 1px;
}

.stpd__rule--wall::before {
	top: 0;
}

.stpd__rule--wall::after {
	bottom: 0;
}

.stpd__rule--wall .stpd__rule-label {
	top: 50%;
	left: 8px;
	transform: translateY(-50%);
}

/* Painting width, just above the painting - below it is exactly where a sofa
   back tends to be, and there is always clear wall overhead. */
.stpd__rule--painting-w {
	left: 50%;
	transform: translateX(-50%);
	width: calc(var(--stpd-p-w) * var(--cm));
	bottom: calc(var(--stpd-p-bottom) + (var(--stpd-p-h) + var(--stpd-frame-w)) * var(--cm) + 16px);
	height: 1px;
	background: var(--stpd-rule-ink);
}

.stpd__rule--painting-w::before,
.stpd__rule--painting-w::after {
	top: -5px;
	width: 1px;
	height: 11px;
}

.stpd__rule--painting-w::before {
	left: 0;
}

.stpd__rule--painting-w::after {
	right: 0;
}

.stpd__rule--painting-w .stpd__rule-label {
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
}

/* Painting height, hugging its right edge. */
.stpd__rule--painting-h {
	left: calc(50% + (var(--stpd-p-w) * var(--cm)) / 2 + var(--stpd-frame-w) * var(--cm) + 16px);
	bottom: var(--stpd-p-bottom);
	height: calc(var(--stpd-p-h) * var(--cm));
	width: 1px;
	background: var(--stpd-rule-ink);
}

.stpd__rule--painting-h::before,
.stpd__rule--painting-h::after {
	left: -5px;
	width: 11px;
	height: 1px;
}

.stpd__rule--painting-h::before {
	top: 0;
}

.stpd__rule--painting-h::after {
	bottom: 0;
}

.stpd__rule--painting-h .stpd__rule-label {
	top: 50%;
	left: 8px;
	transform: translateY(-50%);
}

.stpd__vignette {
	position: absolute;
	inset: 0;
	z-index: 7;
	pointer-events: none;
	background: radial-gradient(120% 90% at 50% 35%, rgba(0, 0, 0, 0) 45%, rgba(0, 0, 0, 0.14));
}

/* ------------------------------------------------------------------ */
/* Caption                                                             */
/* ------------------------------------------------------------------ */

.stpd__caption {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
}

.stpd__caption-text {
	min-width: 0;
}

.stpd__title {
	margin: 0 0 4px;
	font-size: 1.15rem;
	line-height: 1.25;
	font-weight: 600;
	color: var(--stpd-title-text, var(--stpd-ink));
	/* Wraps between words normally, and breaks inside one only when a single
	   word is genuinely wider than the space left for it. */
	overflow-wrap: break-word;
}

.stpd__meta {
	margin: 0;
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 10px;
	color: var(--stpd-meta-text, var(--stpd-muted));
	font-size: 0.9rem;
}

.stpd__meta .stpd__price {
	color: var(--stpd-price-text, var(--stpd-ink));
}

.stpd__meta .stpd__price del {
	opacity: 0.5;
}

.stpd__cta {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 11px 20px;
	border-radius: 999px;
	background: var(--stpd-cta-bg, var(--stpd-accent));
	color: var(--stpd-cta-text, var(--stpd-accent-text));
	font-size: 0.92rem;
	font-weight: 600;
	text-decoration: none;
	white-space: nowrap;
	transition: transform 0.15s ease, opacity 0.15s ease;
}

.stpd__cta:hover,
.stpd__cta:focus-visible {
	background: var(--stpd-cta-hover-bg, var(--stpd-cta-bg, var(--stpd-accent)));
	color: var(--stpd-cta-hover-text, var(--stpd-cta-text, var(--stpd-accent-text)));
	opacity: 0.88;
	transform: translateY(-1px);
}

/* ------------------------------------------------------------------ */
/* Control panel                                                       */
/* ------------------------------------------------------------------ */

.stpd__panel {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
	gap: 18px 24px;
	padding: 20px;
	border: 1px solid var(--stpd-panel-border, var(--stpd-line));
	border-radius: var(--stpd-radius);
	background: var(--stpd-panel-bg, var(--stpd-surface));
}

/* The heading size is set in px from the admin, with its own value for
   narrow layouts. 11.5px matches the 0.72rem this used to be. */
.stpd__group-title {
	margin: 0 0 10px;
	font-size: var(--stpd-group-title-size-wide, 11.5px);
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--stpd-group-title, var(--stpd-muted));
}

.stpd .stpd__thumbs {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.stpd .stpd__thumb {
	width: 52px;
	height: 52px;
	padding: 0;
	border: 2px solid var(--stpd-thumb-border, transparent);
	border-radius: 8px;
	background: var(--stpd-thumb-bg, var(--stpd-surface-2));
	overflow: hidden;
	cursor: pointer;
	transition: border-color 0.15s ease, transform 0.15s ease;
}

.stpd .stpd__thumb img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

@media (hover: hover) {
	.stpd .stpd__thumb:hover {
		transform: translateY(-2px);
		background: var(--stpd-thumb-hover-bg, var(--stpd-thumb-bg, var(--stpd-surface-2)));
		border-color: var(--stpd-thumb-hover-border, var(--stpd-thumb-border, transparent));
	}
}

.stpd .stpd__thumb.is-active {
	border-color: var(--stpd-thumb-border-active, var(--stpd-accent));
}

.stpd .stpd__swatches {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

/* The colour is also set inline on each button, so even a theme rule that
   wins here cannot flatten every swatch to the same shade. */
.stpd .stpd__swatch {
	position: relative;
	width: 34px;
	height: 34px;
	padding: 0;
	border: 1px solid var(--stpd-swatch-border, rgba(0, 0, 0, 0.14));
	border-radius: 50%;
	background-color: var(--stpd-swatch, #fff);
	background-image: none;
	cursor: pointer;
	transition: transform 0.15s ease, box-shadow 0.15s ease;
}

@media (hover: hover) {
	.stpd .stpd__swatch:hover {
		transform: translateY(-2px);
		border-color: var(--stpd-swatch-hover-border, var(--stpd-swatch-border, rgba(0, 0, 0, 0.14)));
	}

	.stpd .stpd__swatch--frame:hover {
		border-color: var(--stpd-fswatch-hover-border, var(--stpd-fswatch-border, rgba(0, 0, 0, 0.2)));
	}
}

.stpd .stpd__swatch.is-active {
	box-shadow:
		0 0 0 2px var(--stpd-panel-bg, var(--stpd-surface)),
		0 0 0 4px var(--stpd-swatch-ring, var(--stpd-accent));
}

.stpd .stpd__swatch--custom {
	display: grid;
	place-items: center;
	overflow: hidden;
	background-image: conic-gradient(from 0deg, #f36, #fc3, #3f6, #3cf, #63f, #f36);
}

.stpd .stpd__swatch--custom input[type="color"] {
	width: 200%;
	height: 200%;
	border: 0;
	padding: 0;
	background: transparent;
	opacity: 0;
	cursor: pointer;
}

/* Frame swatches carry a gradient for the metallic finishes, so unlike the
   wall swatches they cannot take their colour from a single custom property
   - the whole background is set inline per button. */
.stpd .stpd__swatch--frame {
	border-color: var(--stpd-fswatch-border, rgba(0, 0, 0, 0.2));
	border-radius: 6px;
}

.stpd .stpd__swatch--frame.is-active {
	box-shadow:
		0 0 0 2px var(--stpd-panel-bg, var(--stpd-surface)),
		0 0 0 4px var(--stpd-fswatch-ring, var(--stpd-accent));
}

/* ------------------------------------------------------------------ */
/* Frame thickness slider                                              */
/* ------------------------------------------------------------------ */

.stpd__slider {
	display: grid;
	gap: 7px;
	margin-top: 12px;
}

.stpd__slider-head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 10px;
	font-size: 0.85rem;
}

.stpd__slider-value {
	color: var(--stpd-muted);
	font-variant-numeric: tabular-nums;
}

.stpd .stpd__range {
	-webkit-appearance: none;
	appearance: none;
	width: 100%;
	margin: 0;
	padding: 0;
	height: 16px;
	background: transparent;
	border: 0;
	cursor: pointer;
}

/* --stpd-range-pct is kept up to date by JS; Firefox has a real progress
   pseudo-element for this, WebKit has to fake it with a hard-stopped
   gradient across the track. */
.stpd .stpd__range::-webkit-slider-runnable-track {
	height: 5px;
	border-radius: 999px;
	background: linear-gradient(
		to right,
		var(--stpd-slider-fill, var(--stpd-accent)) 0 var(--stpd-range-pct, 40%),
		var(--stpd-slider-track, var(--stpd-toggle-off)) var(--stpd-range-pct, 40%) 100%
	);
}

.stpd .stpd__range::-webkit-slider-thumb {
	-webkit-appearance: none;
	appearance: none;
	width: 16px;
	height: 16px;
	margin-top: -5.5px;
	border: 2px solid var(--stpd-slider-fill, var(--stpd-accent));
	border-radius: 50%;
	background: var(--stpd-slider-thumb, var(--stpd-toggle-knob));
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
}

.stpd .stpd__range::-moz-range-track {
	height: 5px;
	border-radius: 999px;
	background: var(--stpd-slider-track, var(--stpd-toggle-off));
}

.stpd .stpd__range::-moz-range-progress {
	height: 5px;
	border-radius: 999px;
	background: var(--stpd-slider-fill, var(--stpd-accent));
}

.stpd .stpd__range::-moz-range-thumb {
	width: 12px;
	height: 12px;
	border: 2px solid var(--stpd-slider-fill, var(--stpd-accent));
	border-radius: 50%;
	background: var(--stpd-slider-thumb, var(--stpd-toggle-knob));
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
}

.stpd .stpd__chips {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.stpd .stpd__chip {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 7px 13px 7px 8px;
	border: 1px solid var(--stpd-chip-border, var(--stpd-line));
	border-radius: 999px;
	background: var(--stpd-chip-bg, var(--stpd-surface));
	font-size: 0.85rem;
	color: var(--stpd-chip-text, var(--stpd-ink));
	cursor: pointer;
	transition: border-color 0.15s ease, background 0.15s ease;
}

@media (hover: hover) {
	.stpd .stpd__chip:hover {
		background: var(--stpd-chip-hover-bg, var(--stpd-surface-2));
		color: var(--stpd-chip-hover-text, var(--stpd-chip-text, var(--stpd-ink)));
		border-color: var(--stpd-chip-hover-border, var(--stpd-chip-border, var(--stpd-line)));
	}
}

.stpd .stpd__chip.is-active {
	border-color: var(--stpd-chip-active-border, var(--stpd-accent));
	background: var(--stpd-chip-active-bg, var(--stpd-surface-2));
	color: var(--stpd-chip-active-text, var(--stpd-chip-text, var(--stpd-ink)));
	font-weight: 600;
}

.stpd .stpd__chip-dot {
	width: 18px;
	height: 18px;
	border-radius: 50%;
	border: 1px solid rgba(0, 0, 0, 0.14);
	background-size: cover;
	background-position: center;
	flex: 0 0 auto;
}

.stpd__toggles {
	display: grid;
	gap: 10px;
}

.stpd__toggle {
	display: flex;
	align-items: center;
	gap: 10px;
	cursor: pointer;
	font-size: 0.9rem;
}

.stpd__toggle input {
	position: absolute;
	opacity: 0;
	width: 0;
	height: 0;
}

.stpd__toggle-ui {
	position: relative;
	flex: 0 0 auto;
	width: 38px;
	height: 22px;
	border-radius: 999px;
	background: var(--stpd-toggle-off);
	transition: background 0.18s ease;
}

.stpd__toggle-ui::after {
	content: "";
	position: absolute;
	top: 3px;
	left: 3px;
	width: 16px;
	height: 16px;
	border-radius: 50%;
	background: var(--stpd-toggle-knob);
	box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
	transition: transform 0.18s ease;
}

.stpd__toggle input:checked + .stpd__toggle-ui {
	background: var(--stpd-toggle-on, var(--stpd-accent));
}

.stpd__toggle input:checked + .stpd__toggle-ui::after {
	transform: translateX(16px);
}

.stpd__toggle input:focus-visible + .stpd__toggle-ui {
	outline: 2px solid var(--stpd-focus, var(--stpd-accent));
	outline-offset: 2px;
}

.stpd__toggle-text small {
	display: block;
	color: var(--stpd-muted);
	font-size: 0.75rem;
}

.stpd .stpd__thumb:focus-visible,
.stpd .stpd__swatch:focus-visible,
.stpd .stpd__chip:focus-visible,
.stpd .stpd__range:focus-visible,
.stpd__cta:focus-visible {
	outline: 2px solid var(--stpd-focus, var(--stpd-accent));
	outline-offset: 2px;
}

/* Narrow layouts: the camera steps closer, and the controls stack rather than
   squeezing into unusable columns. */
@container (max-width: 520px) {
	.stpd__group-title {
		font-size: var(--stpd-group-title-size-narrow, var(--stpd-group-title-size-wide, 11.5px));
	}

	/* The camera steps closer on a narrow screen, so the painting does not
	   shrink to a stamp. */
	.stpd__scene {
		--stpd-wall-w: var(--stpd-wall-w-narrow, var(--stpd-wall-w-wide, 400));
	}

	.stpd .stpd__nav {
		width: 38px;
		height: 38px;
	}

	.stpd .stpd__nav--prev {
		left: 8px;
	}

	.stpd .stpd__nav--next {
		right: 8px;
	}

	.stpd--rulers .stpd__nav--prev {
		left: 40px;
	}

	.stpd__panel {
		grid-template-columns: 1fr;
		padding: 16px;
	}

	/* The name and the button stay side by side here too. When the name is
	   too long for the space left beside the button, it wraps onto another
	   line rather than pushing the button down onto one of its own. */
	.stpd__caption {
		flex-wrap: nowrap;
		align-items: center;
	}

	.stpd__caption-text {
		flex: 1 1 auto;
	}

	.stpd__cta {
		flex: 0 0 auto;
		/* A little tighter, so the name keeps as much of the row as it can. */
		padding: 10px 16px;
	}
}

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

.stpd-notice {
	padding: 12px 16px;
	border-left: 4px solid #d63638;
	background: #fcf0f1;
	color: #1c1c1e;
	font-size: 0.9rem;
}

/* The frame group stacks a switch, a row of finishes and a slider, so it
   needs a little more air between them than a single-control group. */
.stpd__group--frame .stpd__swatches {
	margin-top: 12px;
}
