/* DNF Smart Quote - split dashboard */

.dnf3dq {
	/* Theme tokens - --dnf-primary / --dnf-accent are also set inline from admin. */
	--dnf-primary: #4938c9;
	--dnf-accent: #4938c9;
	--dnf-surface: #ffffff;
	--dnf-surface-2: #f4f4f6;
	--dnf-surface-3: #f7f8ff;
	--dnf-border: #e2e2e8;
	--dnf-border-2: #d5d5de;
	--dnf-text: #1a1a2e;
	--dnf-muted: #6b6b7b;
	--dnf-faint: #9a9aa8;
	--dnf-hover: #b9c6ff;
	/* Interaction tokens. Overridden inline from the admin's colours, so every
	   button hover and field focus ring follows the chosen colour. */
	--dnf-primary-hover: #3a2ca8;
	--dnf-accent-hover: #3a2ca8;
	--dnf-on-primary: #ffffff;
	--dnf-ring: rgba( 73, 56, 201, 0.18 );
	/* Destructive actions (Start over). Kept as tokens so they follow dark mode
	   like everything else, rather than being pinned to one hardcoded shade. */
	--dnf-danger: #b42318;
	--dnf-danger-bg: #fef3f2;
	--dnf-danger-border: #f7bab4;

	max-width: 1400px;
	margin: 0 auto;
	font-family: var( --dnf-font, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif );
	color: var(--dnf-text);
}

/* ---- Defend against aggressive theme CSS (surgical, so our own spacing is
   untouched). Themes commonly restyle the measurement <dl> (grid/margins),
   which squashed the dimension rows, and reset form-control fonts. We only
   override those specific things, by #id so we win on specificity. */

/* Force the admin-chosen plugin font on EVERY element in the form. Block themes
   set font-family directly on headings (h2/h3/h4), which otherwise beats our
   root font by inheritance and leaves step titles in the theme's font. The #id
   selector + !important guarantees the plugin font wins on any theme. */
#dnf3dq-root,
#dnf3dq-root * {
	font-family: var( --dnf-font, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif ) !important;
}
/* When Next / Back scrolls the wizard to the top of the page, leave a little
   breathing room above it instead of butting against the very top edge. */
#dnf3dq-root {
	scroll-margin-top: 28px;
}
#dnf3dq-root .dnf3dq__meas {
	display: block;
}
#dnf3dq-root .dnf3dq__meas > div {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
}
#dnf3dq-root .dnf3dq__meas dt,
#dnf3dq-root .dnf3dq__meas dd {
	margin: 0;
	padding: 0;
	white-space: nowrap;
}

/* ---- Dark mode: auto (visitor pref) or forced via data-mode ---- */
@media ( prefers-color-scheme: dark ) {
	.dnf3dq[ data-mode="auto" ] {
		--dnf-surface: #1e1e28;
		--dnf-surface-2: #262633;
		--dnf-surface-3: #2b2b3a;
		--dnf-border: #383846;
		--dnf-border-2: #454557;
		--dnf-text: #ecedf2;
		--dnf-muted: #a9aabb;
		--dnf-faint: #8486a0;
		--dnf-hover: #4a4b7a;
		--dnf-danger: #ff9d95;
		--dnf-danger-bg: #3a2220;
		--dnf-danger-border: #7a3b35;
	}
}
.dnf3dq[ data-mode="dark" ] {
	--dnf-surface: #1e1e28;
	--dnf-surface-2: #262633;
	--dnf-surface-3: #2b2b3a;
	--dnf-border: #383846;
	--dnf-border-2: #454557;
	--dnf-text: #ecedf2;
	--dnf-muted: #a9aabb;
	--dnf-faint: #8486a0;
	--dnf-hover: #4a4b7a;
	--dnf-danger: #ff9d95;
	--dnf-danger-bg: #3a2220;
	--dnf-danger-border: #7a3b35;
}

/* Step 2 configure: viewer + controls side by side. */
.dnf3dq__configure {
	display: grid;
	grid-template-columns: 1fr 340px;
	gap: 20px;
}

@media ( max-width: 782px ) {
	.dnf3dq__configure {
		grid-template-columns: 1fr;
	}
}

/* ---- Wizard progress header ---- */
.dnf3dq__steps {
	list-style: none;
	margin: 0 0 22px;
	padding: 0;
	display: flex;
	gap: 8px;
}

.dnf3dq__stepdot {
	flex: 1;
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 13px;
	font-weight: 600;
	color: var(--dnf-faint);
	padding: 10px 12px;
	border-radius: 8px;
	background: var(--dnf-surface-2);
	border: 1px solid var(--dnf-border);
	cursor: default;
	user-select: none;
}

.dnf3dq__stepnum {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 22px;
	height: 22px;
	border-radius: 50%;
	background: var(--dnf-border-2);
	color: #fff;
	font-size: 12px;
	flex: 0 0 auto;
}

.dnf3dq__stepdot.is-active {
	color: var(--dnf-text);
	border-color: var(--dnf-primary);
	background: var(--dnf-surface-3);
}

.dnf3dq__stepdot.is-active .dnf3dq__stepnum {
	background: var(--dnf-primary);
}

.dnf3dq__stepdot.is-done {
	color: #1e7e34;
	cursor: pointer;
}

.dnf3dq__stepdot.is-done .dnf3dq__stepnum {
	background: #1e7e34;
}

.dnf3dq__step-badge {
	margin-left: auto;
	padding: 2px 9px;
	border-radius: 999px;
	background: var(--dnf-accent);
	color: #fff;
	font-size: 11px;
	font-weight: 700;
}
.dnf3dq__step-badge[hidden] {
	display: none !important;
}

/* ---- Wizard nav row ---- */
/* A 3-column grid so the middle button (Start over) is truly centred on the page,
   with Back pinned left and Next pinned right. space-between only centres the gaps,
   which left Start over sitting half-a-button right of centre. */
.dnf3dq__nav {
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	margin-top: 22px;
}
.dnf3dq__nav > :first-child {
	grid-column: 1;
	justify-self: start;
}
.dnf3dq__nav > .dnf3dq__startover {
	grid-column: 2;
	justify-self: center;
}
.dnf3dq__nav > :last-child {
	grid-column: 3;
	justify-self: end;
}

.dnf3dq__next,
.dnf3dq__back,
.dnf3dq__startover {
	border: 1px solid transparent;
	border-radius: 8px;
	padding: 10px 16px;
	min-width: 108px;
	font-size: 14px;
	font-weight: 700;
	text-align: center;
	cursor: pointer;
}

.dnf3dq__next {
	background: var(--dnf-primary);
	color: var(--dnf-on-primary);
}

.dnf3dq__next:hover {
	background: var(--dnf-primary-hover);
}

.dnf3dq__next:disabled {
	opacity: 0.45;
	cursor: not-allowed;
}

.dnf3dq__back {
	background: var(--dnf-surface-2);
	color: var(--dnf-text);
	border: 1px solid var(--dnf-border);
}

.dnf3dq__back:hover {
	background: var(--dnf-surface-3);
	border-color: var(--dnf-hover);
}

/* ---- Step 1 loaded confirmation ---- */
.dnf3dq__loaded {
	margin-top: 16px;
	font-size: 13px;
	font-weight: 700;
	color: #1e7e34;
}

/* Start over throws the customer's work away, so it shouldn't compete with Next
   for attention - but it still has to read as a button. An outline in the
   theme's own neutrals keeps it a peer of Back and Next without shouting, and
   the destructive intent shows on hover, at the moment it matters. (The old
   amber fill clashed with the palette and collided with the amber marking a
   changed part; a borderless ghost went too far the other way and stopped
   looking clickable at all.) */
.dnf3dq__startover {
	border-color: var(--dnf-border-2);
	background: var(--dnf-surface);
	color: var(--dnf-muted);
	transition: border-color .15s ease, color .15s ease, background-color .15s ease;
}
.dnf3dq__startover:hover,
.dnf3dq__startover:focus-visible {
	border-color: var(--dnf-danger-border);
	background: var(--dnf-danger-bg);
	color: var(--dnf-danger);
}
.dnf3dq__startover[hidden] {
	display: none !important;
}
/* In the nav bar it sits centred between Back/Next, so drop the stacked margin. */
.dnf3dq__nav .dnf3dq__startover--nav {
	margin-top: 0;
}

/* ---- Step 3 send ---- */
.dnf3dq__send {
	max-width: 560px;
	margin: 0 auto;
	background: var(--dnf-surface);
	border: 1px solid var(--dnf-border);
	border-radius: 12px;
	padding: 24px;
}

.dnf3dq__sendtitle {
	margin: 0 0 16px;
	font-size: 18px;
}

.dnf3dq__summary {
	list-style: none;
	margin: 0 0 8px;
	padding: 0;
}

.dnf3dq__summary li {
	display: flex;
	justify-content: space-between;
	gap: 16px;
	padding: 8px 0;
	border-bottom: 1px solid var(--dnf-border);
	font-size: 14px;
}

.dnf3dq__summary li span {
	color: var(--dnf-muted);
}

/* ---- Multi-part: parts box on the Send Quote summary ---- */
.dnf3dq__summary li.dnf3dq__sumparts {
	display: block;
	padding: 0;
	border-bottom: 1px solid var(--dnf-border);
}
.dnf3dq__sumparts-head {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: 12px;
	padding: 10px 0 8px;
}
.dnf3dq__sumparts-title {
	color: var(--dnf-muted);
	font-size: 14px;
}
.dnf3dq__sumparts-count {
	color: var(--dnf-faint) !important;
	font-size: 12px;
	font-weight: 600;
}
.dnf3dq__sumparts-list {
	border: 1px solid var(--dnf-border);
	border-radius: 8px;
	background: var(--dnf-surface-2);
	overflow: hidden;
	margin-bottom: 10px;
}
/* More than four parts: cap the height and let the list scroll on its own. */
.dnf3dq__sumparts-list.is-scroll {
	max-height: 168px;
	overflow-y: auto;
}
.dnf3dq__sumpart {
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 9px 12px;
	font-size: 13px;
}
.dnf3dq__sumpart + .dnf3dq__sumpart {
	border-top: 1px solid var(--dnf-border);
}
.dnf3dq__sumpart-num {
	flex: 0 0 auto;
	min-width: 20px;
	height: 20px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 0 5px;
	border-radius: 999px;
	background: var(--dnf-surface-3);
	color: var(--dnf-muted);
	font-size: 11px;
	font-weight: 700;
}
.dnf3dq__sumpart-name {
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	color: var(--dnf-text);
	font-weight: 600;
}
.dnf3dq__sumpart-dims {
	flex: 0 0 auto;
	color: var(--dnf-faint);
	font-size: 12px;
	white-space: nowrap;
}
.dnf3dq__sumpart-qty {
	flex: 0 0 auto;
	min-width: 30px;
	text-align: right;
	color: var(--dnf-muted);
	font-weight: 700;
}

.dnf3dq__price--big {
	margin: 18px 0;
}

.dnf3dq__price--big .dnf3dq__price-value {
	font-size: 32px;
}

.dnf3dq__finehint {
	margin-top: 10px;
	font-size: 12px;
	color: var(--dnf-faint);
	text-align: center;
}

/* ---- Upload progress (send step) ---- */
.dnf3dq__upqueue {
	display: flex;
	flex-direction: column;
	gap: 10px;
	margin: 14px 0 4px;
}
.dnf3dq__upqueue[hidden] {
	display: none;
}
.dnf3dq__upfile {
	display: grid;
	grid-template-columns: 1fr auto;
	grid-template-areas:
		"name pct"
		"bar  bar";
	align-items: center;
	gap: 5px 10px;
}
.dnf3dq__upfile-name {
	grid-area: name;
	font-size: 13px;
	font-weight: 600;
	color: var(--dnf-text);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.dnf3dq__upfile-pct {
	grid-area: pct;
	font-size: 12px;
	font-weight: 700;
	color: var(--dnf-muted);
	font-variant-numeric: tabular-nums;
}
.dnf3dq__upfile-bar {
	grid-area: bar;
	height: 7px;
	border-radius: 999px;
	background: var(--dnf-surface-3);
	overflow: hidden;
}
.dnf3dq__upfile-fill {
	display: block;
	height: 100%;
	width: 0;
	border-radius: 999px;
	background: var(--dnf-primary);
	transition: width 0.18s ease;
}
.dnf3dq__upfile.is-done .dnf3dq__upfile-fill {
	background: #1e9e4a;
}
.dnf3dq__upfile.is-done .dnf3dq__upfile-pct {
	color: #1e9e4a;
}
.dnf3dq__upfile.is-error .dnf3dq__upfile-fill {
	background: #e0405a;
}
.dnf3dq__upfile.is-error .dnf3dq__upfile-pct {
	color: #e0405a;
}

.dnf3dq__viewer--tall {
	min-height: 320px;
}

/* ============ Detailed Configure (Step 2) ============ */

.dnf3dq__cfg {
	display: grid;
	grid-template-columns: 340px 1fr 260px;
	gap: 22px;
	align-items: start;
}

@media ( max-width: 1024px ) {
	.dnf3dq__cfg {
		grid-template-columns: 300px 1fr;
	}
	.dnf3dq__cfg-service {
		grid-column: 1 / -1;
	}
}

@media ( max-width: 720px ) {
	.dnf3dq__cfg {
		grid-template-columns: 1fr;
	}
}

/* ---- Part column ---- */
.dnf3dq__part {
	border: 1px solid var(--dnf-border);
	border-radius: 12px;
	padding: 14px;
	background: var(--dnf-surface);
}

.dnf3dq__part-head {
	display: flex;
	align-items: baseline;
	gap: 8px;
}

.dnf3dq__part-title {
	font-weight: 800;
}

.dnf3dq__part-size {
	color: var(--dnf-accent);
	font-size: 13px;
	font-weight: 700;
}

.dnf3dq__part-uploaded {
	margin: 4px 0 10px;
	font-size: 11px;
	color: var(--dnf-faint);
}

.dnf3dq__part-name {
	width: 100%;
	padding: 8px 10px;
	border: 1px solid var(--dnf-border-2);
	border-radius: 8px;
	font-size: 14px;
	box-sizing: border-box;
	margin-bottom: 12px;
	background: var(--dnf-surface-3);
}

.dnf3dq__viewer--thumb {
	min-height: 300px;
	margin-bottom: 12px;
}
/* Configure-step preview: 25% shorter than the default viewer minimum. */
#dnf3dq-viewer-host {
	min-height: 345px;
	height: 345px;
}

.dnf3dq__viewer {
	position: relative;
}

/* Expand button on the preview */
.dnf3dq__expand {
	position: absolute;
	top: 8px;
	right: 8px;
	z-index: 3;
	width: 34px;
	height: 34px;
	border: 0;
	border-radius: 8px;
	background: rgba( 20, 20, 30, 0.55 );
	color: #fff;
	font-size: 17px;
	line-height: 1;
	cursor: pointer;
}

.dnf3dq__expand:hover {
	background: rgba( 20, 20, 30, 0.8 );
}

/* Light/dark toggle for the preview backdrop (top-left of the preview). */
.dnf3dq__preview-toggle {
	position: absolute;
	top: 8px;
	left: 8px;
	z-index: 3;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 34px;
	height: 34px;
	border: 0;
	border-radius: 8px;
	background: rgba( 20, 20, 30, 0.55 );
	color: #fff;
	cursor: pointer;
}
.dnf3dq__preview-toggle:hover {
	background: rgba( 20, 20, 30, 0.8 );
}
/* Show the moon when the preview is light (click to darken); the sun when dark. */
.dnf3dq__pt-sun {
	display: none;
}
#dnf3dq-root.is-preview-dark .dnf3dq__pt-moon {
	display: none;
}
#dnf3dq-root.is-preview-dark .dnf3dq__pt-sun {
	display: inline;
}
/* In the fullscreen modal, match the larger close button's size and inset. */
.dnf3dq__preview-toggle--modal {
	top: 12px;
	left: 12px;
	width: 38px;
	height: 38px;
	border-radius: 10px;
	z-index: 2;
}

/* Prev/next part arrows on the preview (multi-part quotes). */
.dnf3dq__partnav {
	position: absolute;
	top: 50%;
	transform: translateY( -50% );
	z-index: 3;
	width: 34px;
	height: 44px;
	border: 0;
	border-radius: 8px;
	background: rgba( 20, 20, 30, 0.55 );
	color: #fff;
	font-size: 24px;
	line-height: 1;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
}
.dnf3dq__partnav:hover {
	background: rgba( 20, 20, 30, 0.8 );
}
.dnf3dq__partnav--prev {
	left: 8px;
}
.dnf3dq__partnav--next {
	right: 8px;
}
.dnf3dq__partcounter {
	position: absolute;
	top: 8px;
	left: 8px;
	z-index: 3;
	padding: 3px 9px;
	border-radius: 999px;
	background: rgba( 20, 20, 30, 0.55 );
	color: #fff;
	font-size: 12px;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

.dnf3dq__meas {
	margin: 0 0 12px;
}

.dnf3dq__meas > div {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	padding: 6px 0;
	border-bottom: 1px solid var(--dnf-border);
}

.dnf3dq__meas dt {
	font-size: 12px;
	color: var(--dnf-muted);
	font-weight: 600;
	margin: 0;
}

.dnf3dq__meas dd {
	margin: 0;
	font-size: 13px;
	font-weight: 700;
}

/* ---- Parts list (multi-part quotes) ---- */
.dnf3dq__parts {
	display: flex;
	flex-direction: column;
	gap: 6px;
	margin: 0 0 12px;
	/* Show ~4 rows then scroll so long lists (e.g. a 23-part zip) stay compact. */
	max-height: 216px;
	overflow-y: auto;
	padding-right: 4px;
}
.dnf3dq__partrow {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 6px 8px;
	border: 1px solid var(--dnf-border);
	border-radius: 8px;
	background: var(--dnf-surface);
	transition: border-color .15s ease, background .15s ease;
}
.dnf3dq__partrow.is-active {
	border-color: var(--dnf-accent);
	box-shadow: 0 0 0 1px var(--dnf-accent) inset;
}
.dnf3dq__partrow.is-oversize {
	border-color: #e0405a;
}
.dnf3dq__partpick {
	display: flex;
	align-items: center;
	gap: 8px;
	flex: 1 1 auto;
	min-width: 0;
	border: 0;
	background: none;
	cursor: pointer;
	text-align: left;
	padding: 0;
	color: inherit;
}
/* No black focus box on mouse click - the row's active border already shows the
   selection. Keep a visible ring for keyboard users only. */
.dnf3dq__partpick:focus {
	outline: none;
}
.dnf3dq__partpick:focus-visible {
	outline: 2px solid var(--dnf-accent);
	outline-offset: 2px;
	border-radius: 6px;
}
.dnf3dq__partnum {
	flex: 0 0 auto;
	width: 20px;
	height: 20px;
	border-radius: 50%;
	background: var(--dnf-border);
	color: var(--dnf-text);
	font-size: 11px;
	font-weight: 700;
	display: flex;
	align-items: center;
	justify-content: center;
}
.dnf3dq__partrow.is-active .dnf3dq__partnum {
	background: var(--dnf-accent);
	color: #fff;
}
.dnf3dq__partmeta {
	display: flex;
	flex-direction: column;
	min-width: 0;
}
.dnf3dq__partname-lbl {
	font-size: 13px;
	font-weight: 700;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}
.dnf3dq__partdims {
	font-size: 11px;
	color: var(--dnf-muted);
}
.dnf3dq__partqty {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	gap: 2px;
	font-size: 12px;
	color: var(--dnf-muted);
}
.dnf3dq__partqty input {
	width: 44px;
	padding: 3px 4px;
	border: 1px solid var(--dnf-border);
	border-radius: 6px;
	font-size: 13px;
	text-align: center;
	background: var(--dnf-surface);
	color: var(--dnf-text);
}
.dnf3dq__partdel {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 24px;
	height: 24px;
	padding: 0;
	border: 0;
	border-radius: 6px;
	background: transparent;
	color: var(--dnf-muted);
	cursor: pointer;
	font-size: 15px;
	line-height: 1;
}
.dnf3dq__partdel:hover {
	background: rgba( 224, 64, 90, 0.12 );
	color: #e0405a;
}
.dnf3dq__partdel:focus {
	outline: none;
}
.dnf3dq__partdel:focus-visible {
	outline: 2px solid var(--dnf-accent);
	outline-offset: 1px;
}
.dnf3dq__actions {
	display: flex;
	gap: 8px;
}
.dnf3dq__addmore {
	flex: 1 1 auto;
	border: 1px dashed var(--dnf-border);
	border-radius: 8px;
	background: transparent;
	color: var(--dnf-text);
	font-weight: 600;
	padding: 9px 12px;
	cursor: pointer;
}
.dnf3dq__addmore:hover {
	border-color: var(--dnf-accent);
	color: var(--dnf-accent);
}

.dnf3dq__remove {
	flex: 1 1 auto;
	border: 0;
	border-radius: 8px;
	padding: 10px;
	font-weight: 700;
	cursor: pointer;
	color: #fff;
	background: #e0405a;
}

.dnf3dq__remove:hover {
	background: #c8354d;
}

/* ---- Step titles ---- */
.dnf3dq__cfgstep {
	margin-bottom: 22px;
}

.dnf3dq__cfgstep-title {
	margin: 0 0 12px;
	font-size: 15px;
	font-weight: 700;
	color: var(--dnf-accent);
}

/* "Step N:" prefix slightly muted so the step name reads first. */
.dnf3dq__cfgstep-title span {
	color: var(--dnf-muted);
	font-weight: 600;
}

.dnf3dq__cfgstep-title--on {
	color: var(--dnf-accent);
}

/* ---- Material cards ---- */
.dnf3dq__materials {
	display: grid;
	grid-template-columns: repeat( auto-fill, minmax( 210px, 1fr ) );
	gap: 12px;
}

.dnf3dq__mat {
	position: relative;
	text-align: left;
	border: 2px solid var(--dnf-border);
	border-radius: 12px;
	padding: 16px 16px 0;
	background: var(--dnf-surface);
	color: var(--dnf-text);
	cursor: pointer;
	overflow: hidden;
	transition: border-color 0.12s ease, box-shadow 0.12s ease;
}

.dnf3dq__mat:hover {
	border-color: var(--dnf-hover);
}

.dnf3dq__mat.is-selected {
	border-color: var(--dnf-accent);
}

.dnf3dq__mat-check {
	position: absolute;
	top: 16px;
	right: 16px;
	width: 24px;
	height: 24px;
	border: 2px solid var(--dnf-border-2);
	border-radius: 7px;
	background: var(--dnf-surface);
	display: flex;
	align-items: center;
	justify-content: center;
	transition: background 0.12s ease, border-color 0.12s ease;
}

.dnf3dq__mat.is-selected .dnf3dq__mat-check {
	border-color: var(--dnf-accent);
	background: var(--dnf-accent);
}

.dnf3dq__mat.is-selected .dnf3dq__mat-check::after {
	content: "";
	width: 6px;
	height: 11px;
	margin-top: -2px;
	border: solid #fff;
	border-width: 0 2px 2px 0;
	transform: rotate(45deg);
}

.dnf3dq__mat-name {
	display: block;
	font-weight: 800;
	font-size: 14px;
	padding-right: 34px;
	min-height: 24px;
	color: var(--dnf-text);
}

.dnf3dq__mat-sub {
	display: block;
	font-size: 12px;
	color: var(--dnf-faint);
	margin-top: 2px;
}

.dnf3dq__mat-qty {
	position: absolute;
	left: 16px;
	bottom: 9px;
	font-size: 11px;
	color: var(--dnf-faint);
}

.dnf3dq__mat-prices {
	display: flex;
	margin: 14px -16px 0;
	border-top: 1px solid var(--dnf-border);
	background: var(--dnf-surface-2);
	padding: 8px 16px 8px 40px;
	gap: 12px;
}

.dnf3dq__mat-col {
	display: flex;
	flex-direction: column;
	gap: 2px;
}

.dnf3dq__mat-svc {
	font-size: 10px;
	text-transform: uppercase;
	letter-spacing: 0.02em;
	color: var(--dnf-faint);
}

.dnf3dq__mat-val {
	font-size: 13px;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	color: var(--dnf-text);
}

.dnf3dq__eco {
	display: inline-block;
	vertical-align: middle;
	margin-left: 6px;
	padding: 1px 8px;
	border-radius: 999px;
	background: #e6f4ea;
	color: #1e7e34;
	border: 1px solid #b7e0c2;
	font-size: 11px;
	font-weight: 700;
	line-height: 1.5;
	letter-spacing: 0.02em;
}

/* ---- Finish / Colour option lists ---- */
.dnf3dq__optlist {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.dnf3dq__locked {
	background: var(--dnf-surface-2);
	border-radius: 8px;
	padding: 18px;
	color: var(--dnf-faint);
	font-size: 14px;
}

.dnf3dq__opt {
	display: flex;
	align-items: center;
	gap: 10px;
	text-align: left;
	border: 1px solid var(--dnf-border);
	border-radius: 8px;
	padding: 12px 14px;
	background: var(--dnf-surface);
	color: var(--dnf-text);
	cursor: pointer;
}

.dnf3dq__opt:hover {
	border-color: var(--dnf-hover);
}

.dnf3dq__opt.is-selected {
	border-color: var(--dnf-accent);
	box-shadow: 0 0 0 1px var(--dnf-accent) inset;
}

.dnf3dq__opt-name {
	font-weight: 600;
	font-size: 14px;
}

.dnf3dq__opt-delta {
	margin-left: auto;
	font-size: 13px;
	font-weight: 700;
	color: var(--dnf-accent);
}

.dnf3dq__swatch {
	width: 20px;
	height: 20px;
	border-radius: 50%;
	border: 1px solid rgba( 0, 0, 0, 0.15 );
	flex: 0 0 auto;
}

.dnf3dq__badge {
	font-size: 11px;
	font-weight: 700;
	color: var(--dnf-muted);
	background: var(--dnf-surface-2);
	border-radius: 20px;
	padding: 2px 8px;
}

/* ---- Quantity ---- */
.dnf3dq__qtyinput {
	width: 100%;
	padding: 11px 12px;
	border: 1px solid var(--dnf-border-2);
	border-radius: 8px;
	font-size: 14px;
	box-sizing: border-box;
}

/* ---- Infill (FDM only) ---- */
.dnf3dq__infill {
	margin-top: 14px;
	padding: 12px;
	background: var(--dnf-surface-3);
	border-radius: 8px;
}

.dnf3dq__infill label {
	display: block;
	font-size: 12px;
	font-weight: 600;
	color: var(--dnf-muted);
	margin-bottom: 6px;
}

.dnf3dq__infill input[ type="range" ] {
	width: 100%;
}

/* ---- Service column ---- */
.dnf3dq__cfg-service {
	border: 1px solid var(--dnf-border);
	border-radius: 12px;
	padding: 16px;
	background: var(--dnf-surface);
}

.dnf3dq__servicelist {
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.dnf3dq__svc {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	text-align: left;
	border: 1px solid var(--dnf-border);
	border-radius: 8px;
	padding: 12px;
	background: var(--dnf-surface);
	color: var(--dnf-text);
	cursor: pointer;
}

.dnf3dq__svc:hover {
	border-color: var(--dnf-hover);
}

.dnf3dq__svc.is-selected {
	border-color: var(--dnf-accent);
	box-shadow: 0 0 0 1px var(--dnf-accent) inset;
}

.dnf3dq__svc.is-unavailable {
	opacity: 0.55;
	cursor: not-allowed;
	background: var(--dnf-muted-bg, rgba( 0, 0, 0, 0.03 ) );
}
.dnf3dq__svc.is-unavailable:hover {
	border-color: var(--dnf-border);
}
.dnf3dq__svc.is-unavailable .dnf3dq__svc-days {
	color: var(--dnf-accent);
	font-weight: 600;
}

.dnf3dq__svc-signin {
	margin: 4px 0 0;
	font-size: 12px;
	color: var(--dnf-muted);
}
.dnf3dq__svc-signin a {
	color: var(--dnf-accent);
	font-weight: 700;
	text-decoration: none;
}
.dnf3dq__svc-signin a:hover {
	text-decoration: underline;
}

.dnf3dq__svc-name {
	display: block;
	font-weight: 700;
	font-size: 14px;
}

.dnf3dq__svc-days {
	display: block;
	font-size: 11px;
	color: var(--dnf-faint);
}

.dnf3dq__svc-val {
	font-weight: 800;
	font-variant-numeric: tabular-nums;
}

.dnf3dq__totalbox {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	margin-top: 16px;
	padding-top: 14px;
	border-top: 2px solid var(--dnf-border);
}

.dnf3dq__totalbox .dnf3dq__price-value {
	font-size: 24px;
	font-weight: 800;
}

/* Viewer / dropzone */
.dnf3dq__viewer {
	position: relative;
	min-height: 460px;
	background: var(--dnf-surface-2);
	border: 1px solid var(--dnf-border);
	border-radius: 12px;
	overflow: hidden;
}

/* The [hidden] attribute must beat the explicit display rules below. */
.dnf3dq__dropzone[hidden],
.dnf3dq__canvas[hidden],
.dnf3dq__dims[hidden] {
	display: none !important;
}

.dnf3dq__dropzone {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	text-align: center;
	padding: 24px;
	cursor: pointer;
	transition: background 0.15s ease;
}

.dnf3dq__dropzone.is-drag {
	background: var(--dnf-surface-3);
	outline: 2px dashed var(--dnf-primary);
	outline-offset: -12px;
}

.dnf3dq__dropzone:focus-visible {
	outline: 2px solid var(--dnf-primary);
	outline-offset: -12px;
}

/* Overlapping document icon that sits above the prompt text. */
.dnf3dq__drop-icon {
	display: block;
	width: 100px;
	height: auto;
	margin: 0 auto 20px;
}

.dnf3dq__drop-title {
	font-weight: 800;
	font-size: 22px;
	margin: 0 0 8px;
	color: var(--dnf-text);
}

.dnf3dq__hint {
	margin: 0 auto;
	max-width: 460px;
	font-size: 13px;
	line-height: 1.5;
	color: var(--dnf-muted);
}

/* Failsafe "Browse" button under the prompt (the whole zone is also clickable). */
.dnf3dq__browse {
	margin-top: 16px;
	background: var(--dnf-primary);
	color: var(--dnf-on-primary);
	border: 0;
	border-radius: 8px;
	padding: 10px 18px;
	font-size: 14px;
	font-weight: 600;
	cursor: pointer;
}

.dnf3dq__browse:hover {
	background: var(--dnf-primary-hover);
}

.dnf3dq__canvas {
	display: block;
	width: 100%;
	height: 100%;
	/* A neutral studio backdrop, fixed regardless of the page theme, so any model
	   colour stays visible - a black part on a dark page would otherwise vanish.
	   The visitor can flip the preview to a dark studio with the toggle button. */
	background: radial-gradient( circle at 50% 36%, #f1f2f6 0%, #dcdfe7 68%, #cbcfd9 100% );
}
#dnf3dq-root.is-preview-dark .dnf3dq__canvas {
	background: radial-gradient( circle at 50% 34%, #2c303c 0%, #202531 66%, #171a23 100% );
}

.dnf3dq__dims {
	position: absolute;
	left: 12px;
	bottom: 12px;
	background: rgba( 26, 26, 46, 0.82 );
	color: #fff;
	font-size: 12px;
	padding: 6px 10px;
	border-radius: 6px;
}

/* Panel */
.dnf3dq__panel {
	background: var(--dnf-surface);
	border: 1px solid var(--dnf-border);
	border-radius: 12px;
	padding: 20px;
}

.dnf3dq__filename {
	font-size: 15px;
	margin: 0 0 16px;
	word-break: break-word;
}

.dnf3dq__field {
	margin-bottom: 14px;
}

.dnf3dq__field label {
	display: block;
	font-size: 12px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	color: var(--dnf-muted);
	margin-bottom: 6px;
}

.dnf3dq__field select,
.dnf3dq__field textarea,
.dnf3dq__field input[ type="number" ],
.dnf3dq__field input[ type="email" ],
.dnf3dq__field input[ type="text" ] {
	width: 100%;
	padding: 9px 10px;
	border: 1px solid var(--dnf-border-2);
	border-radius: 8px;
	font-size: 14px;
	box-sizing: border-box;
	background: var(--dnf-surface);
	color: var(--dnf-text);
	font-family: inherit;
}

.dnf3dq__field textarea {
	resize: vertical;
	min-height: 60px;
}

/* One focus treatment for every field in the app, in the admin's own colour.
   Without this the browser paints its own default highlight (purple in Chrome),
   which is what made some boxes ignore the theme. */
#dnf3dq-root input[ type="text" ]:focus,
#dnf3dq-root input[ type="email" ]:focus,
#dnf3dq-root input[ type="number" ]:focus,
#dnf3dq-root input[ type="tel" ]:focus,
#dnf3dq-root textarea:focus,
#dnf3dq-root select:focus {
	outline: none;
	border-color: var(--dnf-accent);
	box-shadow: 0 0 0 3px var(--dnf-ring);
}

/* Sliders and checkboxes paint themselves with the UA accent unless told. */
#dnf3dq-root input[ type="range" ],
#dnf3dq-root input[ type="checkbox" ],
#dnf3dq-root input[ type="radio" ] {
	accent-color: var(--dnf-accent);
}

/* Keyboard focus ring, same colour, on every interactive control. */
#dnf3dq-root button:focus-visible,
#dnf3dq-root [role="button"]:focus-visible,
#dnf3dq-root input:focus-visible,
#dnf3dq-root textarea:focus-visible,
#dnf3dq-root select:focus-visible {
	outline: 2px solid var(--dnf-accent);
	outline-offset: 2px;
}

.dnf3dq__field input[ type="range" ] {
	width: 100%;
}

.dnf3dq__price {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	margin: 18px 0;
	padding: 14px 16px;
	background: var(--dnf-surface-2);
	border-radius: 10px;
}

.dnf3dq__price-label {
	font-size: 13px;
	font-weight: 600;
	color: var(--dnf-muted);
}

.dnf3dq__price-value {
	font-size: 28px;
	font-weight: 800;
	font-variant-numeric: tabular-nums;
}

.dnf3dq__submit {
	width: 100%;
	background: var(--dnf-primary);
	color: var(--dnf-on-primary);
	border: 0;
	border-radius: 8px;
	padding: 14px;
	font-size: 15px;
	font-weight: 700;
	cursor: pointer;
}

.dnf3dq__submit:disabled {
	opacity: 0.45;
	cursor: not-allowed;
}

.dnf3dq__submit:not( :disabled ):hover {
	background: var(--dnf-primary-hover);
}

.dnf3dq__msg {
	margin-top: 12px;
	font-size: 13px;
	min-height: 18px;
}

/* When there is no status/error text, don't reserve vertical space so the Next
   row keeps the same gap as the top of the step. */
.dnf3dq__msg:empty {
	display: none;
}

.dnf3dq__msg.is-error {
	color: #c0392b;
}

.dnf3dq__msg.is-success {
	color: #1e7e34;
	font-weight: 600;
}

.dnf3dq--done .dnf3dq__submit {
	display: none;
}

/* Shown once the quote is submitted, in place of the (now hidden) submit button,
   so the customer has an obvious way out of the finished form. */
.dnf3dq__home {
	display: block;
	width: 100%;
	margin-top: 14px;
	padding: 14px;
	border: 0;
	border-radius: 8px;
	background: var(--dnf-primary);
	color: var(--dnf-on-primary);
	font-size: 15px;
	font-weight: 700;
	text-align: center;
	text-decoration: none;
	box-sizing: border-box;
	cursor: pointer;
	transition: background 0.15s ease;
}
.dnf3dq__home:hover,
.dnf3dq__home:focus {
	background: var(--dnf-primary-hover);
	color: var(--dnf-on-primary);
	text-decoration: none;
}
.dnf3dq__home[hidden] {
	display: none;
}

/* ---- Toasts ---- */
.dnf3dq__toasts {
	position: fixed;
	top: 20px;
	right: 20px;
	z-index: 100000;
	display: flex;
	flex-direction: column;
	gap: 10px;
	max-width: min(360px, calc(100vw - 40px));
	pointer-events: none;
}

.dnf3dq__toast {
	pointer-events: auto;
	display: flex;
	align-items: flex-start;
	gap: 12px;
	padding: 13px 14px 13px 16px;
	border-radius: 10px;
	font-size: 14px;
	font-weight: 600;
	line-height: 1.4;
	color: #fff;
	background: #2d3436;
	box-shadow: 0 8px 24px rgba( 0, 0, 0, 0.22 );
	opacity: 0;
	transform: translateX( 20px );
	transition: opacity 0.22s ease, transform 0.22s ease;
}

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

.dnf3dq__toast-close {
	flex: 0 0 auto;
	margin: -4px -2px 0 0;
	padding: 0;
	width: 22px;
	height: 22px;
	border: 0;
	border-radius: 5px;
	background: transparent;
	color: inherit;
	font-size: 20px;
	line-height: 22px;
	font-weight: 600;
	cursor: pointer;
	opacity: 0.8;
	transition: opacity 0.15s ease, background 0.15s ease;
}

.dnf3dq__toast-close:hover {
	opacity: 1;
	background: rgba( 255, 255, 255, 0.18 );
}

.dnf3dq__toast.is-in {
	opacity: 1;
	transform: translateX( 0 );
}

.dnf3dq__toast--error {
	background: #c0392b;
}

.dnf3dq__toast--success {
	background: #1e7e34;
}

@media ( max-width: 600px ) {
	.dnf3dq__toasts {
		top: auto;
		bottom: 16px;
		left: 16px;
		right: 16px;
		max-width: none;
	}
}

/* ---- Inputs: dark-mode friendly ---- */
.dnf3dq__part-name,
.dnf3dq__qtyinput {
	background: var(--dnf-surface-3);
	color: var(--dnf-text);
}

.dnf3dq__qtyinput {
	border: 1px solid var(--dnf-border-2);
}

/* ---- Fullscreen preview modal ---- */
body.dnf3dq-modal-open {
	overflow: hidden;
}

.dnf3dq__modal[ hidden ] {
	display: none;
}

/* ---- Loading overlay while reading/parsing uploads ---- */
.dnf3dq__loading {
	position: fixed;
	inset: 0;
	z-index: 100001;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgba( 8, 8, 16, 0.55 );
	backdrop-filter: blur( 2px );
}
.dnf3dq__loading[hidden] {
	display: none !important;
}
.dnf3dq__loading-inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 16px;
	padding: 28px 40px;
	background: var(--dnf-surface);
	border-radius: 14px;
	box-shadow: 0 20px 60px rgba( 0, 0, 0, 0.35 );
}
.dnf3dq__dots {
	display: flex;
	gap: 10px;
	align-items: flex-end;
	height: 22px;
}
.dnf3dq__dots span {
	width: 13px;
	height: 13px;
	border-radius: 50%;
	background: var(--dnf-accent);
	animation: dnf3dq-wave 1.2s ease-in-out infinite;
}
.dnf3dq__dots span:nth-child( 2 ) {
	animation-delay: 0.15s;
}
.dnf3dq__dots span:nth-child( 3 ) {
	animation-delay: 0.3s;
}
@keyframes dnf3dq-wave {
	0%, 60%, 100% { transform: translateY( 0 ); }
	30% { transform: translateY( -14px ); }
}
.dnf3dq__loading-text {
	margin: 0;
	font-size: 15px;
	font-weight: 600;
	color: var(--dnf-text);
}
/* Lock the upload controls while a read is in progress. */
.dnf3dq.is-uploading .dnf3dq__dropzone {
	pointer-events: none;
}
.dnf3dq.is-uploading .dnf3dq__browse,
.dnf3dq.is-uploading .dnf3dq__addmore {
	opacity: 0.5;
	pointer-events: none;
}

.dnf3dq__modal {
	position: fixed;
	inset: 0;
	z-index: 100000;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 24px;
	background: rgba( 8, 8, 16, 0.82 );
}

.dnf3dq__modal-inner {
	position: relative;
	width: min( 1100px, 96vw );
	height: min( 82vh, 820px );
	background: var(--dnf-surface-2);
	border-radius: 14px;
	overflow: hidden;
	box-shadow: 0 24px 60px -12px rgba( 0, 0, 0, 0.6 );
}

.dnf3dq__modal-canvas {
	width: 100%;
	height: 100%;
}

.dnf3dq__modal-canvas canvas {
	display: block;
	width: 100%;
	height: 100%;
}

.dnf3dq__modal-close {
	position: absolute;
	top: 12px;
	right: 12px;
	z-index: 2;
	width: 38px;
	height: 38px;
	border: 0;
	border-radius: 10px;
	background: rgba( 20, 20, 30, 0.6 );
	color: #fff;
	font-size: 17px;
	cursor: pointer;
}

.dnf3dq__modal-close:hover {
	background: rgba( 20, 20, 30, 0.85 );
}

/* ---- Info "ⓘ" button + popup ---- */
.dnf3dq__info-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 18px;
	height: 18px;
	margin-left: 6px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	cursor: pointer;
	background: var(--dnf-accent);
	color: #fff;
	font-size: 11px;
	font-weight: 700;
	font-style: italic;
	font-family: Georgia, "Times New Roman", serif;
	line-height: 1;
	vertical-align: middle;
}
.dnf3dq__info-btn:hover {
	filter: brightness( 0.9 );
}

.dnf3dq__infomodal[ hidden ] {
	display: none;
}
.dnf3dq__infomodal {
	position: fixed;
	inset: 0;
	z-index: 100001;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 20px;
	background: rgba( 8, 8, 16, 0.6 );
}
.dnf3dq__infomodal-inner {
	position: relative;
	width: min( 560px, 94vw );
	max-height: 82vh;
	overflow: auto;
	background: var(--dnf-surface);
	color: var(--dnf-text);
	border: 1px solid var(--dnf-border);
	border-radius: 14px;
	padding: 22px 24px;
	box-shadow: 0 24px 60px -12px rgba( 0, 0, 0, 0.5 );
}
.dnf3dq__infomodal-title {
	margin: 0 0 12px;
	font-size: 18px;
	padding-right: 32px;
}
.dnf3dq__infomodal-close {
	position: absolute;
	top: 12px;
	right: 12px;
	width: 32px;
	height: 32px;
	border: 0;
	border-radius: 8px;
	background: var(--dnf-surface-2);
	color: var(--dnf-text);
	cursor: pointer;
	font-size: 14px;
}
.dnf3dq__info-intro {
	margin: 0 0 6px;
	color: var(--dnf-muted);
	font-size: 14px;
	line-height: 1.5;
}
.dnf3dq__info-sub {
	font-weight: 500;
	font-size: 12px;
	color: var(--dnf-faint);
}

/* Collapsible rows inside info popups */
.dnf3dq__acc-list {
	margin-top: 6px;
	border-top: 1px solid var(--dnf-border);
}
.dnf3dq__acc {
	border-bottom: 1px solid var(--dnf-border);
}
.dnf3dq__acc-head {
	width: 100%;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 10px;
	padding: 12px 2px;
	background: none;
	border: 0;
	cursor: pointer;
	text-align: left;
	font: inherit;
	color: var(--dnf-text);
}
.dnf3dq__acc-title {
	font-weight: 700;
	font-size: 15px;
}
.dnf3dq__acc-chev {
	flex: 0 0 auto;
	color: var(--dnf-faint);
	font-size: 20px;
	line-height: 1;
	transition: transform 0.15s ease;
}
.dnf3dq__acc.is-open .dnf3dq__acc-chev {
	transform: rotate( 90deg );
}
.dnf3dq__acc-body {
	display: none;
	padding: 0 2px 12px;
	font-size: 13px;
	color: var(--dnf-muted);
	line-height: 1.5;
}
.dnf3dq__acc.is-open .dnf3dq__acc-body {
	display: block;
}
.dnf3dq__info-dot {
	display: inline-block;
	width: 14px;
	height: 14px;
	border-radius: 50%;
	border: 1px solid rgba( 0, 0, 0, 0.15 );
	vertical-align: middle;
	margin-right: 6px;
}

/* ---- Step 3: Resize ---- */
.dnf3dq__resize {
	display: grid;
	grid-template-columns: 320px minmax( 0, 640px );
	gap: 28px;
	align-items: start;
	/* Centre the viewer + controls as one balanced block so the wide page
	   doesn't leave a lopsided empty band on the right. */
	justify-content: center;
}
@media ( max-width: 760px ) {
	.dnf3dq__resize {
		grid-template-columns: 1fr;
		justify-content: stretch;
	}
}
.dnf3dq__resize-left {
	display: flex;
	flex-direction: column;
	gap: 12px;
}
.dnf3dq__resize-title {
	margin: 0 0 4px;
	font-size: 18px;
}
.dnf3dq__resize-hint {
	margin: 0 0 16px;
	color: var(--dnf-muted);
	font-size: 13px;
}
.dnf3dq__resize-controls {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	flex-wrap: wrap;
	margin-bottom: 16px;
}
/* Sits opposite the mm/% toggle on the same row, so it borrows that control's
   border, radius and surface. As a bare checkbox and label it read as leftover
   markup next to a properly styled segmented control. */
.dnf3dq__resize-lock {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	padding: 7px 14px;
	border: 1px solid var(--dnf-border-2);
	border-radius: 8px;
	background: var(--dnf-surface-2);
	font-size: 13px;
	font-weight: 600;
	/* Pinned to the line box a <button> resolves 'normal' to at this size, so
	   this label ends up exactly as tall as the mm/% toggle sitting beside it.
	   Left to 'normal' a label and a button differ by a pixel. */
	line-height: 17px;
	cursor: pointer;
	user-select: none;
	transition: border-color .15s ease, background-color .15s ease;
}
.dnf3dq__resize-lock:hover {
	border-color: var(--dnf-hover);
}
/* The native checkbox otherwise renders in the browser's blue, ignoring the
   admin's chosen colour like every other control here follows. */
.dnf3dq__resize-lock input[ type="checkbox" ] {
	accent-color: var(--dnf-accent);
	width: 15px;
	height: 15px;
	margin: 0;
	flex: 0 0 auto;
	cursor: pointer;
}
/* mm / % segmented toggle */
.dnf3dq__mode-toggle {
	display: inline-flex;
	border: 1px solid var(--dnf-border-2);
	border-radius: 8px;
	overflow: hidden;
	background: var(--dnf-surface-2);
}
.dnf3dq__mode-btn {
	border: 0;
	background: none;
	padding: 7px 16px;
	font-size: 13px;
	font-weight: 700;
	color: var(--dnf-muted);
	cursor: pointer;
	min-width: 46px;
}
.dnf3dq__mode-btn + .dnf3dq__mode-btn {
	border-left: 1px solid var(--dnf-border-2);
}
.dnf3dq__mode-btn.is-active {
	background: var(--dnf-accent);
	color: #fff;
}
/* Keep the resize preview compact so the nav buttons stay on screen. */
#dnf3dq-resize-viewer {
	min-height: 0;
	height: 300px;
}
.dnf3dq__resize-grid {
	display: grid;
	grid-template-columns: repeat( 3, minmax( 0, 1fr ) );
	gap: 14px;
	margin-bottom: 16px;
}
@media ( max-width: 520px ) {
	.dnf3dq__resize-grid {
		grid-template-columns: 1fr;
	}
}
.dnf3dq__rz-wrap {
	position: relative;
}
.dnf3dq__rz-input {
	width: 100%;
	box-sizing: border-box;
	padding: 12px 68px 12px 12px;
	border: 1px solid var(--dnf-border-2);
	border-radius: 10px;
	font-size: 16px;
	background: var(--dnf-surface);
	color: var(--dnf-text);
}
.dnf3dq__rz-unit {
	position: absolute;
	right: 36px;
	top: 50%;
	transform: translateY( -50% );
	color: var(--dnf-muted);
	font-size: 13px;
	font-weight: 700;
	pointer-events: none;
	background: var(--dnf-surface);
	padding-left: 4px;
}
.dnf3dq__rz-input:focus {
	outline: none;
	border-color: var(--dnf-accent);
	box-shadow: 0 0 0 3px var(--dnf-ring);
}
.dnf3dq__rz-step {
	position: absolute;
	right: 6px;
	top: 50%;
	transform: translateY( -50% );
	display: flex;
	flex-direction: column;
	gap: 2px;
}
.dnf3dq__rz-step button {
	width: 22px;
	height: 15px;
	padding: 0;
	margin: 0;
	border: 1px solid var(--dnf-border-2);
	background: var(--dnf-surface-2);
	color: var(--dnf-muted);
	border-radius: 5px;
	font-size: 8px;
	line-height: 1;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.dnf3dq__rz-step button:hover {
	background: var(--dnf-accent);
	color: var(--dnf-fill-text);
	border-color: var(--dnf-accent);
}
.dnf3dq__field-hint {
	display: block;
	margin-top: 5px;
	font-size: 12px;
	color: var(--dnf-muted);
}
.dnf3dq__resize-readout {
	padding: 12px 14px;
	border-radius: 10px;
	background: var(--dnf-surface-3);
	border: 1px solid var(--dnf-border);
	font-weight: 700;
	font-size: 14px;
	margin-bottom: 14px;
}
.dnf3dq__rz-sub {
	font-weight: 500;
	font-size: 12px;
	color: var(--dnf-muted);
	margin-top: 3px;
}
/* A real secondary button rather than a bare text link. It was the only action
   on this step not shaped like a button, which is what made it read as stray
   copy sitting under the panels. */
.dnf3dq__resize-reset {
	border: 1px solid var(--dnf-border-2);
	border-radius: 8px;
	background: var(--dnf-surface-2);
	color: var(--dnf-text);
	font-weight: 600;
	font-size: 13px;
	line-height: 1.25;
	padding: 8px 14px;
	cursor: pointer;
	transition: border-color .15s ease, background-color .15s ease;
}
.dnf3dq__resize-reset:hover {
	background: var(--dnf-surface-3);
	border-color: var(--dnf-hover);
}
.dnf3dq__resize-reset:focus-visible {
	outline: 2px solid var(--dnf-accent);
	outline-offset: 2px;
}
/* The control column width is set by the grid track now, so fill it. */
.dnf3dq__resize-main {
	max-width: none;
}
/* Footer: reset link on the left, compact total on the right. */
.dnf3dq__resize-foot {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	margin-top: 4px;
	padding-top: 14px;
	border-top: 1px solid var(--dnf-border);
}
.dnf3dq__resize-total {
	display: flex;
	align-items: baseline;
	gap: 10px;
}
.dnf3dq__resize-total .dnf3dq__price-value {
	font-size: 24px;
	font-weight: 800;
}
/* Clickable part rows on the resize step (no qty/remove controls). */
/* On the Resize step the whole row IS a <button> (on Configure it is a div with
   a button inside). That means the theme's own button styling applies to it: a
   dark border/background, and padding that pushed the row wider than its column
   so it bled off the page. Scoped by #dnf3dq-root so it outranks theme rules
   like `.entry-content button`, and box-sizing so 100% width really is 100%. */
#dnf3dq-root .dnf3dq__partrow--pick {
	width: 100%;
	box-sizing: border-box;
	-webkit-appearance: none;
	appearance: none;
	margin: 0;
	padding: 6px 8px;
	border: 1px solid var(--dnf-border);
	border-radius: 8px;
	background: var(--dnf-surface);
	color: inherit;
	font: inherit;
	text-align: left;
	text-transform: none;
	letter-spacing: normal;
	cursor: pointer;
}
#dnf3dq-root .dnf3dq__partrow--pick.is-active {
	border-color: var(--dnf-accent);
	box-shadow: 0 0 0 1px var(--dnf-accent) inset;
}
#dnf3dq-root .dnf3dq__partrow--pick.is-oversize {
	border-color: #e0405a;
}
/* A part changed away from the quote-wide setup (resized, own infill, own
   colour) gets the same amber wash the admin uses, so it stands out in the list
   without opening each part. */
#dnf3dq-root .dnf3dq__partrow--pick.is-customised {
	background: #fffdf6;
	border-color: #e8cf94;
}
/* data-mode lives on #dnf3dq-root itself, so these have to be compound
   selectors, and carry the id to outrank the light rule above. */
#dnf3dq-root[ data-mode="dark" ] .dnf3dq__partrow--pick.is-customised {
	background: #3a2f20;
	border-color: #7a5a2c;
}
@media (prefers-color-scheme: dark) {
	#dnf3dq-root[ data-mode="auto" ] .dnf3dq__partrow--pick.is-customised {
		background: #3a2f20;
		border-color: #7a5a2c;
	}
}

/* ---- Customise list: "what changed" badges ---- */
.dnf3dq__partbadges {
	display: flex;
	flex-wrap: wrap;
	gap: 3px;
	margin-top: 3px;
}
/* Blue on the amber row: amber-on-amber blended into the highlight, so the badge
   borrows the theme accent instead. That also ties it to the other accent-marked
   things (the Next button, the active row, the price deltas), and follows the
   admin's chosen colour rather than pinning a blue of its own. */
.dnf3dq__partbadge {
	padding: 1px 6px;
	border-radius: 4px;
	border: 1px solid var(--dnf-accent);
	background: #fff;
	color: var(--dnf-accent);
	font-size: 10px;
	font-weight: 700;
	line-height: 1.6;
	white-space: nowrap;
}
/* On a dark row a mid-blue would sink into the background, so the badge goes
   ghosted with a light blue that keeps its contrast. */
#dnf3dq-root[ data-mode="dark" ] .dnf3dq__partbadge {
	border-color: #7f8cff;
	background: transparent;
	color: #b9c6ff;
}
@media (prefers-color-scheme: dark) {
	#dnf3dq-root[ data-mode="auto" ] .dnf3dq__partbadge {
		border-color: #7f8cff;
		background: transparent;
		color: #b9c6ff;
	}
}

/* ---- Customise: field header (label + info icon) ---- */
.dnf3dq__rz-fieldhead {
	display: flex;
	align-items: center;
	/* The icon hugs its label rather than floating out at the panel edge. */
	justify-content: flex-start;
	gap: 0;
}
/* The label's own margin would push the icon out of line with it. */
.dnf3dq__infill .dnf3dq__rz-fieldhead label {
	margin-bottom: 0;
}

/* What the current infill / colour choice adds, sat next to its value. */
.dnf3dq__rz-delta {
	margin-left: 6px;
	font-size: 12px;
	font-weight: 700;
	color: var(--dnf-accent);
}
.dnf3dq__rz-delta[ hidden ] {
	display: none;
}

/* ---- Hover tooltip variant of the round "i" icon ----
   Same button as the Configure steps use, but it explains itself in place
   instead of opening the info modal. */
.dnf3dq__info-btn--tip {
	position: relative;
}
.dnf3dq__info-btn--tip::after {
	content: attr( data-tip );
	position: absolute;
	bottom: calc( 100% + 8px );
	left: 50%;
	transform: translateX( -50% );
	z-index: 6;
	width: max-content;
	max-width: 250px;
	padding: 8px 10px;
	border-radius: 6px;
	background: var(--dnf-text);
	color: var(--dnf-surface);
	/* The icon is a <button>, so the theme's button typography (italic in some
	   themes) would otherwise leak into the bubble. */
	font-family: inherit;
	font-size: 12px;
	font-style: normal;
	font-weight: 500;
	line-height: 1.45;
	letter-spacing: normal;
	text-align: left;
	text-transform: none;
	white-space: normal;
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.15s ease;
	pointer-events: none;
}
/* The little arrow under the bubble. */
.dnf3dq__info-btn--tip::before {
	content: "";
	position: absolute;
	bottom: calc( 100% + 3px );
	left: 50%;
	z-index: 6;
	margin-left: -5px;
	border: 5px solid transparent;
	border-top-color: var(--dnf-text);
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.15s ease;
	pointer-events: none;
}
.dnf3dq__info-btn--tip:hover::after,
.dnf3dq__info-btn--tip:hover::before,
.dnf3dq__info-btn--tip:focus-visible::after,
.dnf3dq__info-btn--tip:focus-visible::before {
	opacity: 1;
	visibility: visible;
}
/* Hovering the icon must not dim it the way the modal ones do. */
.dnf3dq__info-btn--tip:hover {
	filter: none;
}

/* ---- Customise: per-part colour swatches ----
   Sized and bordered like the Configure step's .dnf3dq__swatch so the two read
   as the same control. The selection ring sits outside the dot (with a gap in
   the panel colour) rather than inside it, which would eat into a dark swatch. */
.dnf3dq__rz-swatches {
	display: flex;
	flex-wrap: wrap;
	/* Roomy enough that neighbouring selection rings never touch. */
	gap: 14px;
	margin: 2px 0 10px;
	padding: 3px 3px 0;
}
#dnf3dq-root .dnf3dq__rz-swatch {
	-webkit-appearance: none;
	appearance: none;
	width: 20px;
	height: 20px;
	padding: 0;
	margin: 0;
	border: 0;
	border-radius: 50%;
	background: none;
	cursor: pointer;
	line-height: 0;
}
.dnf3dq__rz-swatch-dot {
	display: block;
	width: 100%;
	height: 100%;
	box-sizing: border-box;
	border-radius: 50%;
	/* A hairline so white and other pale swatches still read as a disc. */
	border: 1px solid rgba( 0, 0, 0, 0.15 );
	transition: box-shadow 0.15s ease;
}
#dnf3dq-root .dnf3dq__rz-swatch:hover .dnf3dq__rz-swatch-dot {
	box-shadow: 0 0 0 2px var(--dnf-surface-3), 0 0 0 3px var(--dnf-border);
}
#dnf3dq-root .dnf3dq__rz-swatch.is-selected .dnf3dq__rz-swatch-dot {
	box-shadow: 0 0 0 2px var(--dnf-surface-3), 0 0 0 4px var(--dnf-accent);
}
#dnf3dq-root .dnf3dq__rz-swatch:focus {
	outline: none;
}
#dnf3dq-root .dnf3dq__rz-swatch:focus-visible .dnf3dq__rz-swatch-dot {
	box-shadow: 0 0 0 2px var(--dnf-surface-3), 0 0 0 4px var(--dnf-accent);
}

/* The colour dot carried by each row in the Customise parts list. */
.dnf3dq__partdot {
	display: inline-block;
	width: 9px;
	height: 9px;
	margin-right: 5px;
	border-radius: 50%;
	vertical-align: baseline;
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25);
}
#dnf3dq-root .dnf3dq__partrow--pick:hover {
	border-color: var(--dnf-hover);
}
/* Clicking must not leave the browser's default (black) focus box behind; the
   ring is kept for keyboard users only, in the theme colour. */
#dnf3dq-root .dnf3dq__partrow--pick:focus {
	outline: none;
}
#dnf3dq-root .dnf3dq__partrow--pick:focus-visible {
	outline: 2px solid var(--dnf-accent);
	outline-offset: 2px;
}

/* ---- Resize: Skipped badge + agreement ---- */
.dnf3dq__badge-skip {
	display: inline-block;
	margin-left: 6px;
	padding: 1px 9px;
	border-radius: 999px;
	background: var(--dnf-accent);
	color: #fff;
	font-size: 11px;
	font-weight: 700;
	vertical-align: middle;
}
.dnf3dq__resize-agree {
	margin: 14px 0 4px;
	padding: 12px 14px;
	border: 1px solid var(--dnf-border-2);
	border-radius: 10px;
	background: var(--dnf-surface-3);
}
.dnf3dq__resize-agree[hidden] {
	display: none !important;
}
.dnf3dq__agree-label {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	font-size: 13px;
	line-height: 1.5;
	cursor: pointer;
}
.dnf3dq__agree-label input[type="checkbox"] {
	margin-top: 2px;
	flex: 0 0 auto;
	width: 18px;
	height: 18px;
}
.dnf3dq__policy-link {
	border: 0;
	background: none;
	padding: 0;
	color: var(--dnf-accent);
	font: inherit;
	font-weight: 700;
	text-decoration: underline;
	cursor: pointer;
}

/* ---- Filled card style (Theme option) ----
   Two tiers, not one. Every card used to be painted the full accent colour, so
   the only thing separating "chosen" from "not chosen" was a thin ring: eight
   identical solid slabs, with nothing to look at and the primary Next button
   competing against all of them.
   Unselected cards are now a soft tint of the accent - still unmistakably the
   filled style, still branded - and the SELECTED card is the full colour. The
   contrast between the two tiers is what makes the choice readable. */
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat,
#dnf3dq-root[data-cards="filled"] .dnf3dq__opt,
#dnf3dq-root[data-cards="filled"] .dnf3dq__svc {
	/* Fallback for browsers without color-mix(): a neutral panel. */
	background: var(--dnf-surface-2);
	border-color: var(--dnf-border-2);
	color: var(--dnf-text);
}
@supports ( background: color-mix( in srgb, red 10%, white ) ) {
	#dnf3dq-root[data-cards="filled"] .dnf3dq__mat,
	#dnf3dq-root[data-cards="filled"] .dnf3dq__opt,
	#dnf3dq-root[data-cards="filled"] .dnf3dq__svc {
		/* Mixed against the surface rather than a fixed white, so this tracks
		   dark mode without a second set of rules. */
		background: color-mix( in srgb, var(--dnf-fill) 8%, var(--dnf-surface) );
		border-color: color-mix( in srgb, var(--dnf-fill) 24%, var(--dnf-surface) );
	}
}
/* The chosen one: full strength. */
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat.is-selected,
#dnf3dq-root[data-cards="filled"] .dnf3dq__opt.is-selected,
#dnf3dq-root[data-cards="filled"] .dnf3dq__svc.is-selected {
	background: var(--dnf-fill);
	border-color: var(--dnf-fill);
	color: var(--dnf-fill-text);
}
/* Text: only the selected card sits on the solid colour, so only it needs the
   reversed-out palette. */
#dnf3dq-root[data-cards="filled"] .is-selected .dnf3dq__mat-name,
#dnf3dq-root[data-cards="filled"] .is-selected .dnf3dq__opt-name,
#dnf3dq-root[data-cards="filled"] .is-selected .dnf3dq__svc-name,
#dnf3dq-root[data-cards="filled"] .is-selected .dnf3dq__opt-delta,
#dnf3dq-root[data-cards="filled"] .is-selected .dnf3dq__svc-val {
	color: var(--dnf-fill-text);
}
#dnf3dq-root[data-cards="filled"] .is-selected .dnf3dq__mat-sub,
#dnf3dq-root[data-cards="filled"] .is-selected .dnf3dq__svc-days {
	color: var(--dnf-fill-sub);
}
/* Unselected keeps the normal reading colours, with the price delta in the
   accent so "Free" and "+10%" still stand out against the tint. */
#dnf3dq-root[data-cards="filled"] .dnf3dq__opt:not( .is-selected ) .dnf3dq__opt-delta,
#dnf3dq-root[data-cards="filled"] .dnf3dq__svc:not( .is-selected ) .dnf3dq__svc-val {
	color: var(--dnf-accent);
}
/* The material price footer keeps the neutral panel colour ("blue header + dark
   footer" like the reference), so its text uses the normal theme colours. */
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat-prices {
	background: var(--dnf-surface-2);
	border-top-color: var(--dnf-border);
	color: var(--dnf-text);
	margin: 14px -16px 0;
	/* No explicit radius: the card's own overflow:hidden clips the footer to the
	   rounded corners. A separate radius here left the purple card background
	   peeking through as nubs at the bottom corners (visible on hover). */
}
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat-val {
	color: var(--dnf-text);
}
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat-svc,
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat-qty {
	color: var(--dnf-faint);
}
/* Consistent, shadow-free feedback on every filled card / option / service. */
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat,
#dnf3dq-root[data-cards="filled"] .dnf3dq__opt,
#dnf3dq-root[data-cards="filled"] .dnf3dq__svc {
	transition: filter 0.14s ease, box-shadow 0.14s ease;
}
/* Hover on an unselected card: deepen the tint towards the accent, so it reads
   as "moving towards chosen". brightness() alone did nothing visible now that
   the resting state is a pale tint rather than a saturated block. */
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat:not( .is-selected ):hover,
#dnf3dq-root[data-cards="filled"] .dnf3dq__opt:not( .is-selected ):hover,
#dnf3dq-root[data-cards="filled"] .dnf3dq__svc:not( .is-selected ):hover {
	border-color: var(--dnf-fill);
}
@supports ( background: color-mix( in srgb, red 10%, white ) ) {
	#dnf3dq-root[data-cards="filled"] .dnf3dq__mat:not( .is-selected ):hover,
	#dnf3dq-root[data-cards="filled"] .dnf3dq__opt:not( .is-selected ):hover,
	#dnf3dq-root[data-cards="filled"] .dnf3dq__svc:not( .is-selected ):hover {
		background: color-mix( in srgb, var(--dnf-fill) 16%, var(--dnf-surface) );
	}
}
/* The selected card is already the only solid one on the screen, so it needs no
   ring on top. The old double ring existed because every card was identical;
   keeping it now would just add noise around the one thing that stands out. */
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat.is-selected:hover,
#dnf3dq-root[data-cards="filled"] .dnf3dq__opt.is-selected:hover,
#dnf3dq-root[data-cards="filled"] .dnf3dq__svc.is-selected:hover {
	filter: brightness( 1.08 );
}
/* Check indicators: reversed out on the selected (solid) card, drawn in the
   accent on the unselected (tinted) ones - a white outline on a pale tint is
   invisible. */
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat-check {
	border-color: var(--dnf-border-2);
	background: transparent;
}
#dnf3dq-root[data-cards="filled"] .is-selected .dnf3dq__mat-check {
	border-color: var(--dnf-fill-text);
}
/* Filled cards: a smaller, less bulky selection box (matches the tighter look). */
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat-check {
	width: 17px;
	height: 17px;
	border-width: 1.5px;
	border-radius: 5px;
	top: 15px;
	right: 15px;
}
/* Trim the tick to suit the smaller filled selection box. */
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat.is-selected .dnf3dq__mat-check::after {
	width: 5px;
	height: 9px;
	border-width: 0 2px 2px 0;
}
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat.is-selected .dnf3dq__mat-check {
	background: var(--dnf-fill-text);
	border-color: var(--dnf-fill-text);
}
#dnf3dq-root[data-cards="filled"] .dnf3dq__mat.is-selected .dnf3dq__mat-check::after {
	border-color: var(--dnf-fill);
}
