/* DTF & DTG Knockout Studio
   Scoped under .dtfk so a theme's own form styling cannot reach in, and built
   on custom properties so a shop can retheme it without touching this file. */

.dtfk {
	--dtfk-ink: #16161a;
	--dtfk-muted: #6b6b76;
	--dtfk-line: #ddd9d0;
	--dtfk-bg: #fbfaf8;
	--dtfk-panel: #fff;
	--dtfk-accent: #ff3b5c;
	--dtfk-good: #15803d;
	--dtfk-warn: #b45309;
	--dtfk-bad: #b91c1c;
	--dtfk-hist: #8a8a96;
	--dtfk-radius: 8px;

	color: var(--dtfk-ink);
	font-size: 14px;
	line-height: 1.5;
}

@media (prefers-color-scheme: dark) {
	.dtfk {
		--dtfk-ink: #ececf1;
		--dtfk-muted: #9b9baa;
		--dtfk-line: #35353f;
		--dtfk-bg: #17171c;
		--dtfk-panel: #1e1e25;
		--dtfk-good: #4ade80;
		--dtfk-warn: #fbbf24;
		--dtfk-bad: #f87171;
		--dtfk-hist: #7d7d8d;
	}
}

/* The root is included on purpose: bleed() sets its width to clientWidth, and
   the inline padding above has to sit inside that, not add to it. */
.dtfk, .dtfk *, .dtfk *::before, .dtfk *::after { box-sizing: border-box; }

/* ── Mode tabs ───────────────────────────────────────────────────────── */

.dtfk-modes { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 14px; }

.dtfk-mode {
	padding: 8px 16px;
	border: 1px solid var(--dtfk-line);
	border-radius: 999px;
	background: var(--dtfk-panel);
	color: var(--dtfk-muted);
	font: inherit;
	font-weight: 600;
	cursor: pointer;
}

.dtfk-mode.is-on {
	border-color: var(--dtfk-accent);
	background: var(--dtfk-accent);
	color: #fff;
}

.dtfk-mode-note {
	flex: 1 1 100%;
	margin: 2px 0 0;
	color: var(--dtfk-muted);
	font-size: 12.5px;
}

/* ── Drop zone ───────────────────────────────────────────────────────── */

.dtfk-drop {
	display: flex;
	flex-direction: column;
	gap: 6px;
	align-items: center;
	justify-content: center;
	min-height: 220px;
	padding: 32px;
	border: 2px dashed var(--dtfk-line);
	border-radius: var(--dtfk-radius);
	background: var(--dtfk-bg);
	text-align: center;
	cursor: pointer;
}

.dtfk-drop:hover, .dtfk-drop:focus-visible, .dtfk-drop.is-over {
	border-color: var(--dtfk-accent);
	background: color-mix(in srgb, var(--dtfk-accent) 6%, var(--dtfk-bg));
}

.dtfk-drop strong { font-size: 17px; }
.dtfk-drop span { color: var(--dtfk-muted); font-size: 13px; }

/* ── Full-bleed ──────────────────────────────────────────────────────── */

/* Most themes cap the content column at 700-900px, which leaves this tool
   squeezed into a strip while the canvas is the whole point.

   The breakout itself is applied by bleed() in knockout.js, which measures
   where the theme's column actually sits. The tempting CSS-only version —
     width: 100vw; margin-left: calc(50% - 50vw);
   — only lands correctly when the parent column is *centred* in the viewport.
   fotogravat.ro's theme left-aligns it, and that exact rule dragged the
   photobook editor 601px off-screen at 1920px; see that plugin's DEPLOY.md.
   100vw also counts the scrollbar, adding overflow. Measuring sidesteps both.

   So the CSS fallback deliberately does nothing but sit inside the column:
   narrower than ideal if the script fails, but never clipped.

   width="page" on the shortcode opts out of the breakout entirely. */
.dtfk-full {
	width: auto;
	max-width: none;
	margin: 0;
	padding-inline: clamp(14px, 2.5vw, 48px);
}

/* ── Layout ──────────────────────────────────────────────────────────── */

.dtfk-studio {
	display: grid;
	grid-template-columns: minmax(0, 1.6fr) minmax(300px, 1fr);
	gap: 18px;
	align-items: start;
}

@media (max-width: 900px) {
	.dtfk-studio { grid-template-columns: minmax(0, 1fr); }
}

/* Past this width the panel rail turns into a tall thin ribbon with the stage
   swallowing the rest, so give the controls a second column instead. CSS
   columns rather than a grid: the panels are all different heights, and a grid
   would align their rows and leave ragged gaps. */
@media (min-width: 1500px) {
	.dtfk-studio { grid-template-columns: minmax(0, 1.9fr) minmax(620px, 1fr); }
	.dtfk-panels { display: block; column-count: 2; column-gap: 14px; }
	.dtfk-panel { break-inside: avoid; margin-bottom: 14px; }
}

.dtfk-stage { min-width: 0; }

/* The canvas holds still while the controls scroll past it.

   Sticky works here because the grid uses align-items:start, so the stage's
   track is as tall as the taller panels column and the stage has room to
   travel inside it. Capping the stage's own height is what keeps it on screen:
   an element taller than the viewport sticks at its bottom edge and scrolls
   away at the top, which would defeat the point.

   Only above the breakpoint — stacked on a phone the canvas is above the
   controls and pinning it would leave nothing to read. */
@media (min-width: 901px) {
	.dtfk-stage {
		position: sticky;
		top: var(--dtfk-sticky-top, 16px);
		align-self: start;
	}

	/* Room for the stage bar, the stats line and the top offset, so the whole
	   stage fits the viewport rather than just the canvas. */
	.dtfk-canvas-wrap[data-zoom="fit"] canvas { max-height: calc(100vh - 190px); }
	.dtfk-canvas-wrap:not([data-zoom="fit"]) { height: calc(100vh - 190px); }
}

/* The WordPress toolbar is fixed over the top of the page for logged-in users
   and would clip the stage bar. */
.admin-bar .dtfk { --dtfk-sticky-top: 48px; }

.dtfk-stage-bar {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	align-items: center;
	margin-bottom: 8px;
	color: var(--dtfk-muted);
	font-size: 12.5px;
}

.dtfk-dims, .dtfk-size { font-weight: 600; color: var(--dtfk-ink); }
.dtfk-spacer { flex: 1 1 auto; }
.dtfk-sep { opacity: .5; }

/* The checkerboard is what makes transparency readable; the garment colour
   replaces it when previewing on cloth, which is where halos show up. */
.dtfk-canvas-wrap {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 12px;
	border: 1px solid var(--dtfk-line);
	border-radius: var(--dtfk-radius);
	background-color: #fff;
	background-image:
		linear-gradient(45deg, #e6e6e6 25%, transparent 25%),
		linear-gradient(-45deg, #e6e6e6 25%, transparent 25%),
		linear-gradient(45deg, transparent 75%, #e6e6e6 75%),
		linear-gradient(-45deg, transparent 75%, #e6e6e6 75%);
	background-size: 18px 18px;
	background-position: 0 0, 0 9px, 9px -9px, -9px 0;
	overflow: auto;
}

.dtfk-canvas-wrap.is-shirt { background-image: none; }

/* Both maxima with auto width and height: the browser's replaced-element sizing
   then shrinks the box itself, keeping its rect exactly the painted area. That
   is what the eyedropper depends on — object-fit would letterbox inside a
   larger box and every picked coordinate would be off. */
.dtfk-canvas-wrap canvas { display: block; }

.dtfk-canvas-wrap[data-zoom="fit"] canvas {
	max-width: 100%;
	max-height: 72vh;
	width: auto;
	height: auto;
}

/* Zoomed in, the wrapper becomes the viewport and scrolls. Nearest-neighbour is
   deliberate: at 400% the point is to inspect individual halftone dots and
   knockout edges, and smoothing would invent pixels that are not in the file. */
.dtfk-canvas-wrap:not([data-zoom="fit"]) {
	height: 72vh;
	align-items: flex-start;
	justify-content: flex-start;
}

.dtfk-canvas-wrap:not([data-zoom="fit"]) canvas {
	flex: 0 0 auto;
	max-width: none;
	max-height: none;
	image-rendering: pixelated;
	image-rendering: crisp-edges;
}

.dtfk-zoom-label {
	min-width: 3.4em;
	font-variant-numeric: tabular-nums;
	color: var(--dtfk-muted);
}

.dtfk-stats { margin: 8px 0 0; color: var(--dtfk-muted); font-size: 12.5px; min-height: 1.4em; }

/* ── Panels ──────────────────────────────────────────────────────────── */

.dtfk-panels { display: flex; flex-direction: column; gap: 14px; min-width: 0; }

.dtfk-panel {
	padding: 14px 16px 16px;
	border: 1px solid var(--dtfk-line);
	border-radius: var(--dtfk-radius);
	background: var(--dtfk-panel);
}

.dtfk-panel-key { border-left: 3px solid var(--dtfk-accent); }

.dtfk-panel h3 {
	display: flex;
	gap: 10px;
	align-items: center;
	margin: 0 0 10px;
	font-size: 12px;
	font-weight: 700;
	letter-spacing: .07em;
	text-transform: uppercase;
	color: var(--dtfk-muted);
}

/* The on/off switch sits in the heading because the whole panel is one stage of
   the pipeline — there is no "apply" any more, so this is what apply became. */
.dtfk-toggle {
	display: inline-flex;
	gap: 5px;
	align-items: center;
	margin-left: auto;
	font-size: 11px;
	letter-spacing: .04em;
	cursor: pointer;
}

.dtfk-toggle input { accent-color: var(--dtfk-accent); }

/* ── Levels ──────────────────────────────────────────────────────────── */

.dtfk-lv { margin-bottom: 12px; }

.dtfk-hist {
	display: block;
	width: 100%;
	height: 88px;
	border: 1px solid var(--dtfk-line);
	border-bottom: 0;
	border-radius: 6px 6px 0 0;
	background: var(--dtfk-bg);
	/* The canvas is 256 wide for one column per tone; let it stretch. */
	image-rendering: auto;
}

.dtfk-lv-track {
	position: relative;
	height: 16px;
	margin-bottom: 8px;
	border: 1px solid var(--dtfk-line);
	border-radius: 0 0 6px 6px;
	background: linear-gradient(to right, #000, #fff);
}

/* The output track is the same gradient read as a destination range, so it gets
   its own rounded box rather than hanging off the histogram. */
.dtfk-lv-out { border-radius: 6px; margin-top: 4px; }

/* A triangle pointing up at the track, the way the dialog draws them.

   Drawn as two stacked triangles because clip-path throws the border away — a
   bordered box clipped to a triangle loses the border with the corners. The
   outer one IS the outline, so the white marker stays visible on a white panel
   and the black one on a dark panel; using --dtfk-ink for it means the outline
   flips with the theme while the fills stay literal black, grey and white. */
.dtfk-lv-handle {
	position: absolute;
	top: 100%;
	width: 16px;
	height: 13px;
	margin-left: -8px;
	cursor: ew-resize;
	touch-action: none;
	clip-path: polygon(50% 0, 100% 100%, 0 100%);
	background: var(--dtfk-ink);
}

.dtfk-lv-handle::after {
	content: '';
	position: absolute;
	left: 2px;
	top: 3px;
	width: 12px;
	height: 9px;
	clip-path: polygon(50% 0, 100% 100%, 0 100%);
	background: currentColor;
}

.dtfk-lv-handle.is-black { color: #101014; }
.dtfk-lv-handle.is-gamma { color: #9a9aa6; }
.dtfk-lv-handle.is-white { color: #fff; }

.dtfk-lv-handle:hover { background: var(--dtfk-accent); }

.dtfk-lv-handle.is-drag, .dtfk-lv-handle:focus-visible {
	background: var(--dtfk-accent);
	outline: none;
}

/* The focus ring cannot sit on a clipped element either, so the parent track
   carries it and keyboard users still see which marker has focus. */
.dtfk-lv-handle:focus-visible::after { background: var(--dtfk-accent); }

.dtfk-lv-nums {
	display: grid;
	grid-template-columns: 1fr 1fr 1fr;
	gap: 6px;
	margin: 12px 0 4px;
}

.dtfk-lv-nums-two { grid-template-columns: 1fr 1fr; }
.dtfk-lv-nums input { width: 100%; text-align: center; }

.dtfk-lv-label {
	display: block;
	margin: 14px 0 5px;
	font-size: 12.5px;
	font-weight: 600;
}

.dtfk-row { margin-bottom: 12px; min-width: 0; }
.dtfk-row:last-child { margin-bottom: 0; }

.dtfk-row > label {
	display: flex;
	gap: 6px;
	align-items: baseline;
	margin-bottom: 5px;
	font-size: 12.5px;
	font-weight: 600;
}

.dtfk-row > label output { color: var(--dtfk-accent); font-variant-numeric: tabular-nums; }

.dtfk-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

.dtfk-inline { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }

.dtfk-hint { margin: 5px 0 0; color: var(--dtfk-muted); font-size: 11.5px; line-height: 1.45; }
.dtfk-hint.is-good { color: var(--dtfk-good); }
.dtfk-hint.is-warn { color: var(--dtfk-warn); }
.dtfk-hint.is-bad  { color: var(--dtfk-bad); }
.dtfk-note { font-variant-numeric: tabular-nums; }

.dtfk-unit { color: var(--dtfk-muted); font-weight: 400; }

/* ── Controls ────────────────────────────────────────────────────────── */

.dtfk input[type="text"],
.dtfk input[type="number"],
.dtfk select {
	min-width: 0;
	padding: 7px 9px;
	border: 1px solid var(--dtfk-line);
	border-radius: 6px;
	background: var(--dtfk-bg);
	color: var(--dtfk-ink);
	font: inherit;
	font-size: 13px;
}

.dtfk .dtfk-row > input[type="number"],
.dtfk .dtfk-row > select { width: 100%; }

.dtfk input[type="range"] { width: 100%; accent-color: var(--dtfk-accent); }

.dtfk input[type="color"] {
	width: 34px;
	height: 32px;
	padding: 2px;
	border: 1px solid var(--dtfk-line);
	border-radius: 6px;
	background: var(--dtfk-bg);
	cursor: pointer;
}

.dtfk-hex { width: 88px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

.dtfk-check {
	display: flex;
	gap: 7px;
	align-items: center;
	font-size: 12.5px;
	cursor: pointer;
}

.dtfk-check input { accent-color: var(--dtfk-accent); }

.dtfk-btn {
	padding: 8px 14px;
	border: 1px solid transparent;
	border-radius: 6px;
	font: inherit;
	font-size: 13px;
	font-weight: 600;
	line-height: 1.2;
	text-decoration: none;
	cursor: pointer;
}

.dtfk-btn-primary { background: var(--dtfk-accent); color: #fff; }
.dtfk-btn-primary:hover { filter: brightness(1.08); }

.dtfk-btn-ghost {
	border-color: var(--dtfk-line);
	background: transparent;
	color: var(--dtfk-ink);
}

.dtfk-btn:disabled { opacity: .5; cursor: not-allowed; }

.dtfk-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.dtfk-actions-top { margin-top: 0; margin-bottom: 4px; }

/* Size, colour and the rest, two axes to a row where there is space. */
.dtfk-variations {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
	gap: 10px;
	margin-bottom: 10px;
}

.dtfk-variations .dtfk-row { margin-bottom: 0; }
.dtfk-variations select { width: 100%; }

.dtfk-pick, .dtfk-auto {
	padding: 0 10px;
	min-width: 34px;
	height: 32px;
	border: 1px solid var(--dtfk-line);
	border-radius: 6px;
	background: var(--dtfk-bg);
	color: var(--dtfk-ink);
	font: inherit;
	font-size: 13px;
	cursor: pointer;
}

.dtfk-pick.is-on { border-color: var(--dtfk-accent); background: var(--dtfk-accent); color: #fff; }

.dtfk-segment { display: inline-flex; border: 1px solid var(--dtfk-line); border-radius: 6px; overflow: hidden; }

.dtfk-segment button {
	padding: 6px 14px;
	border: 0;
	background: var(--dtfk-bg);
	color: var(--dtfk-muted);
	font: inherit;
	font-size: 12.5px;
	font-weight: 600;
	cursor: pointer;
}

.dtfk-segment button.is-on { background: var(--dtfk-accent); color: #fff; }

.dtfk-presets { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: 10px; font-size: 12px; color: var(--dtfk-muted); }

.dtfk-presets button {
	padding: 5px 10px;
	border: 1px solid var(--dtfk-line);
	border-radius: 999px;
	background: transparent;
	color: var(--dtfk-ink);
	font: inherit;
	font-size: 12px;
	cursor: pointer;
}

.dtfk-presets button:hover { border-color: var(--dtfk-accent); color: var(--dtfk-accent); }

/* ── Verdicts and the spec list ──────────────────────────────────────── */

.dtfk-verdict {
	margin: 10px 0 0;
	padding: 9px 11px;
	border-radius: 6px;
	background: var(--dtfk-bg);
	font-size: 12px;
	line-height: 1.45;
}

.dtfk-verdict.is-good { color: var(--dtfk-good); background: color-mix(in srgb, var(--dtfk-good) 10%, transparent); }
.dtfk-verdict.is-warn { color: var(--dtfk-warn); background: color-mix(in srgb, var(--dtfk-warn) 10%, transparent); }
.dtfk-verdict.is-bad  { color: var(--dtfk-bad);  background: color-mix(in srgb, var(--dtfk-bad)  10%, transparent); }

.dtfk-spec {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 4px 14px;
	margin: 0 0 12px;
	font-size: 12.5px;
}

.dtfk-spec dt { margin: 0; color: var(--dtfk-muted); }

.dtfk-spec dd {
	margin: 0;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
	overflow-wrap: anywhere;
}

/* ── Garment swatches ────────────────────────────────────────────────── */

.dtfk-swatches { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 10px; }

.dtfk-swatch {
	width: 34px;
	height: 34px;
	padding: 3px;
	border: 1px solid var(--dtfk-line);
	border-radius: 7px;
	background: var(--dtfk-bg);
	cursor: pointer;
}

.dtfk-swatch span {
	display: block;
	width: 100%;
	height: 100%;
	border-radius: 4px;
	/* An inset edge so a white garment still reads as a swatch, not a gap. */
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .18);
}

.dtfk-swatch.is-on { border-color: var(--dtfk-accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--dtfk-accent) 30%, transparent); }

.dtfk-garment-custom { margin-bottom: 4px; }
.dtfk-garment-name { font-size: 12.5px; font-weight: 600; }

.dtfk-choke-mm { margin-left: auto; color: var(--dtfk-muted); font-weight: 400; font-variant-numeric: tabular-nums; }
.dtfk-btn-small { margin-top: 8px; padding: 5px 10px; font-size: 12px; }

/* ── Shop garments ───────────────────────────────────────────────────── */

.dtfk-products {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
	gap: 8px;
	margin-bottom: 14px;
}

.dtfk-product {
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding: 7px;
	border: 1px solid var(--dtfk-line);
	border-radius: 7px;
	background: var(--dtfk-bg);
	color: inherit;
	font: inherit;
	text-align: left;
	cursor: pointer;
}

.dtfk-product img, .dtfk-product-noimg {
	display: block;
	width: 100%;
	aspect-ratio: 1;
	object-fit: cover;
	border-radius: 5px;
	background: var(--dtfk-panel);
}

.dtfk-product-name { font-size: 12px; font-weight: 600; line-height: 1.3; }
.dtfk-product-price { font-size: 11.5px; color: var(--dtfk-muted); }

.dtfk-product.is-on {
	border-color: var(--dtfk-accent);
	box-shadow: 0 0 0 2px color-mix(in srgb, var(--dtfk-accent) 28%, transparent);
}

.dtfk-result { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 12px 0 0; font-size: 12.5px; }
.dtfk-result.is-good { color: var(--dtfk-good); }
.dtfk-result.is-warn { color: var(--dtfk-warn); }
.dtfk-result.is-bad  { color: var(--dtfk-bad); }

/* The drop zone, the studio and the underbase panel are all toggled with the
   hidden attribute. Plenty of themes set display on bare element selectors and
   quietly beat it, so make it win here. */
.dtfk [hidden] { display: none !important; }
