/* ==========================================================================
   QR Code Generator & Campaign Tracker - page-scoped styles. Prefix: .qg-
   Uses the Venuera design tokens (see DESIGN-SYSTEM.md). No shared component
   is redefined here and main.css is untouched.
   ========================================================================== */

.qg-hero {
	padding: calc(var(--header-h) + 72px) 0 40px;
	background: radial-gradient(900px 400px at 50% -10%, var(--paper-tint), transparent 70%), var(--paper);
}
.qg-hero-meta { color: var(--muted); margin-top: 18px; }

/* ==========================================================================
   Board (dark) - the working surface
   ========================================================================== */
/* The override that makes the pinned code column work at all.
   main.css gives every .v-dark section "overflow:hidden", which quietly turns
   this section into the scrollport for the sticky code column inside it - and
   because the section itself never scrolls, sticky never engages and the code
   scrolls away with the page. Releasing the overflow here (main.css is not
   touched) hands the job back to the viewport, where it belongs.
   Nothing is lost by it: the aurora wash and the film grain are both
   "position:absolute; inset:0", so they are bounded by this element whatever
   the overflow says, and main.css already sets "overflow-x:hidden" on <body>
   as the backstop against any sideways spill. "overflow:clip" would also let
   sticky work, but Safari below 16 drops the declaration and falls straight
   back to the inherited "hidden" - so plain "visible" it is. */
.qg-board-section {
	position: relative; padding-top: 52px; padding-bottom: 64px;
	overflow: visible;
}
.qg-board { position: relative; }

/* ---- mode tabs ---- */
.qg-tabs {
	display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 22px;
	background: var(--ink-900); border: 1px solid var(--d-line); border-radius: 999px; padding: 6px;
	width: fit-content; max-width: 100%;
}
.qg-tab {
	appearance: none; cursor: pointer; border: 0; background: none; color: var(--d-muted);
	font: 600 13.5px var(--body); padding: 9px 18px; border-radius: 999px;
	display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
	transition: background .15s, color .15s;
}
.qg-tab svg { width: 15px; height: 15px; flex: none; }
.qg-tab:hover { color: var(--d-head); }
.qg-tab.is-on { background: var(--violet); color: #fff; }

.qg-panel { display: none; }
.qg-panel.is-on { display: block; }

/* ---- shared dark surfaces ---- */
.qg-card {
	background: var(--ink-850); border: 1px solid var(--d-line); border-radius: var(--r);
	padding: 20px 22px;
}
.qg-card + .qg-card { margin-top: 16px; }
.qg-k {
	font: 500 10.5px var(--mono); text-transform: uppercase; letter-spacing: .08em;
	color: var(--d-faint); margin: 0 0 12px;
}
.qg-card h3 {
	font-family: var(--display); font-size: 16px; font-weight: 600; color: var(--d-head);
	letter-spacing: -0.01em; margin: 0 0 8px;
}
/* Only paragraphs with no class of their own get the generic card treatment.
   Every qg- classed paragraph inside a card (.qg-k, .qg-hint, .qg-warn,
   .qg-empty, .qg-pop-k, .qg-row-*) keeps exactly what its own class says. */
.qg-card p:not([class]) { color: var(--d-muted); font-size: 13.5px; margin: 0 0 10px; }
.qg-card p:not([class]):last-child { margin-bottom: 0; }
.qg-card p:not([class]) b { color: var(--d-head); font-weight: 600; }
.qg-hint { color: var(--d-faint); font-size: 12.5px; line-height: 1.55; margin: 0; }
.qg-hint b { color: var(--d-muted); font-weight: 600; }

/* The small spacing helpers (.qg-mt, .qg-mt-l) used to live here, and living
   here is what broke them: they are single-class rules, so any component rule
   further down the file that writes the "margin" shorthand silently resets the
   margin-top they were asked for. .qg-sublab does exactly that, which is why
   every heading in the design panel sat flush against the row above it. They
   are now at the very bottom of this file, where a utility belongs. */
.qg-vh {
	position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
	clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; opacity: 0; pointer-events: none;
}

.qg-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.02fr); gap: 16px; }
.qg-cols-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; margin-top: 16px; }
.qg-cols-2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; margin-top: 16px; }

/* ---- buttons ---- */
.qg-btn {
	appearance: none; cursor: pointer; display: inline-flex; align-items: center; gap: 8px;
	background: var(--ink-850); color: var(--d-text); border: 1px solid var(--d-line);
	font: 600 13px var(--body); padding: 9px 14px; border-radius: var(--r-sm);
	transition: background .15s, color .15s, border-color .15s, transform .08s;
	white-space: nowrap;
}
.qg-btn:hover { background: var(--ink-800); color: var(--d-head); border-color: var(--d-line-2); }
.qg-btn:active { transform: translateY(1px); }
.qg-btn svg { width: 15px; height: 15px; flex: none; }
.qg-btn[disabled] { opacity: .4; cursor: default; }
.qg-btn[disabled]:hover { background: var(--ink-850); color: var(--d-text); border-color: var(--d-line); }
.qg-btn-primary { background: var(--violet); border-color: transparent; color: #fff; }
.qg-btn-primary:hover { background: var(--violet-l); border-color: transparent; color: #fff; }
.qg-btn-sm { font-size: 12px; padding: 7px 11px; }
.qg-btn.is-danger:hover { background: rgba(180, 35, 31, .22); color: #FFD9D7; border-color: rgba(180, 35, 31, .5); }
.qg-btnrow { display: flex; gap: 8px; flex-wrap: wrap; }

/* ---- content-type chips ---- */
.qg-types { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 18px; }
.qg-type {
	appearance: none; cursor: pointer; display: inline-flex; align-items: center; gap: 7px;
	background: var(--ink-900); border: 1px solid var(--d-line); color: var(--d-muted);
	font: 600 12.5px var(--body); padding: 8px 13px; border-radius: 999px;
	transition: background .15s, color .15s, border-color .15s;
}
.qg-type svg { width: 14px; height: 14px; flex: none; }
.qg-type:hover { color: var(--d-head); border-color: var(--d-line-2); }
.qg-type.is-on {
	background: color-mix(in srgb, var(--violet) 26%, var(--ink-850));
	border-color: color-mix(in srgb, var(--violet) 58%, transparent); color: var(--d-head);
}

/* ---- form fields ---- */
.qg-form { display: grid; gap: 12px; }
.qg-field { display: grid; gap: 6px; min-width: 0; }
.qg-field label { font: 500 12.5px var(--body); color: var(--d-muted); }
.qg-field label span { color: var(--d-faint); font-weight: 400; }
.qg-in {
	width: 100%; background: var(--ink-900); border: 1px solid var(--d-line-2); color: var(--d-head);
	font: 500 13.5px var(--body); padding: 10px 12px; border-radius: var(--r-sm);
	min-width: 0;
}
.qg-in::placeholder { color: var(--d-faint); }
.qg-in:focus { outline: 2px solid var(--violet); outline-offset: 1px; }
.qg-in.is-mono { font-family: var(--mono); font-size: 12.5px; }
textarea.qg-in { resize: vertical; min-height: 92px; line-height: 1.55; }
select.qg-in { cursor: pointer; }
.qg-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.qg-check { display: flex; align-items: flex-start; gap: 9px; }
.qg-check input { margin: 2px 0 0; accent-color: var(--violet); width: 15px; height: 15px; flex: none; }
.qg-check label { font: 500 12.5px var(--body); color: var(--d-muted); cursor: pointer; }
.qg-check label small { display: block; color: var(--d-faint); font-weight: 400; margin-top: 2px; }

/* ---- live preview ---- */
.qg-out { display: grid; gap: 16px; align-content: start; }
.qg-stage {
	background: #fff; border-radius: var(--r); padding: 22px;
	display: grid; place-items: center; min-height: 260px;
	box-shadow: inset 0 0 0 1px rgba(20, 18, 31, .1);
}
.qg-stage svg { display: block; width: 100%; max-width: 232px; height: auto; }
.qg-stage.is-empty { color: #74748A; font: 500 13px var(--body); text-align: center; }
.qg-stage-note {
	font: 500 10.5px var(--mono); text-transform: uppercase; letter-spacing: .08em;
	color: #74748A; margin: 12px 0 0; text-align: center;
}

.qg-facts { display: grid; gap: 0; margin: 0; }
.qg-facts > div {
	display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
	padding: 9px 0; border-bottom: 1px solid var(--d-line);
}
.qg-facts > div:last-child { border-bottom: 0; }
.qg-facts dt { font: 500 12.5px var(--body); color: var(--d-muted); margin: 0; }
.qg-facts dd {
	margin: 0; font: 600 13px var(--mono); color: var(--d-head);
	font-variant-numeric: tabular-nums; text-align: right;
}
.qg-facts dd small { display: block; font-family: var(--body); font-weight: 400; font-size: 11.5px; color: var(--d-faint); margin-top: 2px; }
.qg-facts > div.is-warn dd { color: var(--amber); }
.qg-facts > div.is-bad dd { color: #FF8E88; }

/* ---- size presets ---- */
.qg-sizes { display: grid; gap: 8px; }
.qg-size {
	appearance: none; cursor: pointer; text-align: left; width: 100%;
	background: var(--ink-900); border: 1px solid var(--d-line); border-radius: var(--r-sm);
	padding: 10px 13px; color: var(--d-text);
	display: flex; align-items: baseline; gap: 10px;
	transition: background .15s, border-color .15s;
}
.qg-size:hover { border-color: var(--d-line-2); background: var(--ink-800); }
.qg-size.is-on {
	background: color-mix(in srgb, var(--violet) 22%, var(--ink-850));
	border-color: color-mix(in srgb, var(--violet) 58%, transparent);
}
.qg-size b { font: 600 13px var(--body); color: var(--d-head); }
.qg-size i {
	font-style: normal; font: 600 12.5px var(--mono); color: var(--d-muted);
	margin-left: auto; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.qg-size.is-on i { color: var(--d-head); }
.qg-size span { font-size: 11.5px; color: var(--d-faint); }
.qg-custom { display: none; align-items: center; gap: 8px; margin-top: 10px; }
.qg-custom.is-on { display: flex; }
.qg-custom label { font: 500 12.5px var(--body); color: var(--d-muted); }
.qg-custom .qg-in { width: 96px; font-family: var(--mono); }

/* ---- colours ---- */
.qg-colors { display: grid; gap: 12px; }
.qg-colorrow { display: flex; align-items: center; gap: 10px; }
.qg-colorrow label { font: 500 12.5px var(--body); color: var(--d-muted); width: 88px; flex: none; }
.qg-colorrow input[type="color"] {
	appearance: none; width: 40px; height: 32px; padding: 0; cursor: pointer;
	background: none; border: 1px solid var(--d-line-2); border-radius: 8px;
}
.qg-colorrow input[type="color"]::-webkit-color-swatch-wrapper { padding: 3px; }
.qg-colorrow input[type="color"]::-webkit-color-swatch { border: 0; border-radius: 5px; }
.qg-colorrow .qg-in { width: 108px; font-family: var(--mono); font-size: 12.5px; text-transform: uppercase; }
.qg-presets-c { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 2px; }
.qg-swatch {
	appearance: none; cursor: pointer; width: 26px; height: 26px; border-radius: 8px; padding: 0;
	border: 1px solid var(--d-line-2); position: relative; overflow: hidden;
}
.qg-swatch i { position: absolute; inset: 0; display: block; }
.qg-swatch i::after {
	content: ''; position: absolute; inset: 5px; border-radius: 2px; background: currentColor;
}

/* ---- damage levels ---- */
.qg-levels { display: grid; gap: 8px; }
.qg-level {
	appearance: none; cursor: pointer; text-align: left; width: 100%;
	background: var(--ink-900); border: 1px solid var(--d-line); border-radius: var(--r-sm);
	padding: 10px 13px; color: var(--d-text);
	transition: background .15s, border-color .15s;
}
.qg-level:hover { border-color: var(--d-line-2); background: var(--ink-800); }
.qg-level.is-on {
	background: color-mix(in srgb, var(--violet) 22%, var(--ink-850));
	border-color: color-mix(in srgb, var(--violet) 58%, transparent);
}
.qg-level b {
	font: 600 13px var(--body); color: var(--d-head);
	display: flex; align-items: baseline; gap: 8px;
}
.qg-level b i {
	font-style: normal; margin-left: auto; font: 500 11px var(--mono); color: var(--d-faint);
	text-transform: uppercase; letter-spacing: .06em;
}
.qg-level span { display: block; font-size: 12px; color: var(--d-muted); margin-top: 3px; line-height: 1.5; }

/* ---- pre-print checks ---- */
.qg-checks { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.qg-checks li {
	display: flex; align-items: flex-start; gap: 10px;
	font-size: 13px; color: var(--d-text); line-height: 1.55;
}
/* A check line often quotes the link back, and a link has no spaces in it - so
   without these two the longest one sets the width of the whole column and the
   card grows wider than the phone it is being read on. */
.qg-checks li p { margin: 0; font-size: inherit; color: inherit; min-width: 0; overflow-wrap: anywhere; }
.qg-checks li b { color: var(--d-head); font-weight: 600; }
.qg-checks li svg { width: 16px; height: 16px; flex: none; margin-top: 2px; }
.qg-checks li.is-ok svg { color: var(--green); }
.qg-checks li.is-warn svg { color: var(--amber); }
.qg-checks li.is-bad svg { color: #FF8E88; }
.qg-checks li.is-bad { color: #FFD9D7; }

/* ---- placement spec ---- */
.qg-spec {
	background: var(--ink-900); border: 1px solid var(--d-line); border-radius: var(--r-sm);
	padding: 14px 16px; margin: 0 0 12px; overflow-x: auto;
	font: 500 12px/1.75 var(--mono); color: var(--d-text); white-space: pre;
}

/* ---- print pieces ---- */
.qg-pieces { display: grid; gap: 8px; }
.qg-piece {
	appearance: none; cursor: pointer; text-align: left; width: 100%;
	background: var(--ink-900); border: 1px solid var(--d-line); border-radius: var(--r-sm);
	padding: 11px 13px; color: var(--d-text);
	display: flex; align-items: center; gap: 11px;
	transition: background .15s, border-color .15s;
}
.qg-piece:hover { border-color: var(--d-line-2); background: var(--ink-800); }
.qg-piece.is-on {
	background: color-mix(in srgb, var(--violet) 22%, var(--ink-850));
	border-color: color-mix(in srgb, var(--violet) 58%, transparent);
}
.qg-piece svg { width: 22px; height: 22px; flex: none; color: var(--d-muted); }
.qg-piece > div { min-width: 0; }
.qg-piece.is-on svg { color: var(--violet-l); }
.qg-piece b { font: 600 13px var(--body); color: var(--d-head); display: block; }
.qg-piece span { font-size: 11.5px; color: var(--d-faint); }

/* ---- batch mode ---- */
.qg-batch-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.qg-batch-head .qg-k { margin: 0; }
.qg-batch-head span.qg-sp { flex: 1 1 20px; }
.qg-batch-head label.qg-hint { margin: 0; }
.qg-batch-head .qg-in { width: 78px; font-family: var(--mono); text-align: center; }
.qg-batch-head .qg-in.is-narrow { width: 62px; }
.qg-list { display: grid; gap: 8px; max-height: 520px; overflow-y: auto; padding-right: 4px; }
.qg-row {
	display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 14px; align-items: center;
	background: var(--ink-900); border: 1px solid var(--d-line); border-radius: var(--r-sm); padding: 10px 12px;
}
.qg-row.is-bad { border-color: rgba(180, 35, 31, .55); }
.qg-row-qr { background: #fff; border-radius: 6px; padding: 5px; display: grid; place-items: center; }
.qg-row-qr svg { display: block; width: 100%; height: auto; }
.qg-row-qr.is-none {
	background: var(--ink-800); color: var(--d-faint); font: 500 10px var(--mono);
	text-align: center; padding: 12px 6px; text-transform: uppercase; letter-spacing: .06em;
}
.qg-row-b { min-width: 0; }
.qg-row-lab { font: 600 13.5px var(--body); color: var(--d-head); margin: 0 0 3px; }
.qg-row-val {
	font: 500 12px var(--mono); color: var(--d-muted); margin: 0;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.qg-row-meta { font-size: 11.5px; color: var(--d-faint); margin: 5px 0 0; }
.qg-row-meta.is-bad { color: #FF8E88; }
.qg-row-meta b { color: var(--d-muted); font-weight: 600; }

/* ---- campaign tracker ---- */
/* "position: relative" is not decoration. The table has a visually hidden
   heading on the remove column, and a visually hidden element is positioned
   absolutely - so without a positioned wrapper its containing block is the
   whole board, which means the wrapper's overflow does not clip it and that one
   1px span sits 940px to the right, dragging a horizontal scrollbar across the
   entire page on a phone. Positioning the wrapper puts it back inside the clip. */
.qg-tablewrap {
	position: relative;
	overflow-x: auto; border: 1px solid var(--d-line); border-radius: var(--r);
}
.qg-table { width: 100%; border-collapse: collapse; min-width: 940px; }
.qg-table th {
	font: 500 10.5px var(--mono); text-transform: uppercase; letter-spacing: .08em;
	color: var(--d-faint); text-align: left; padding: 11px 12px; background: var(--ink-900);
	border-bottom: 1px solid var(--d-line); white-space: nowrap;
}
.qg-table td {
	padding: 10px 12px; border-bottom: 1px solid var(--d-line); vertical-align: middle;
	font-size: 13px; color: var(--d-text);
}
.qg-table tr:last-child td { border-bottom: 0; }
.qg-table tr.is-dup td { background: rgba(180, 120, 20, .12); }
.qg-table .qg-in { padding: 7px 9px; font-size: 12.5px; }
.qg-ch { display: flex; align-items: center; gap: 9px; min-width: 150px; }
.qg-ch svg { width: 16px; height: 16px; flex: none; color: var(--d-muted); }
.qg-ch > div { min-width: 0; }
.qg-ch b { font: 600 13px var(--body); color: var(--d-head); }
.qg-ch span { display: block; font-size: 11px; color: var(--d-faint); }
.qg-linkcell { min-width: 260px; }
.qg-linkcell code {
	display: block; font: 500 11.5px/1.6 var(--mono); color: var(--d-muted);
	word-break: break-all; background: none; padding: 0;
}
.qg-tqr { width: 92px; }
.qg-tqr .qg-row-qr { padding: 4px; }
.qg-tqr label {
	display: flex; align-items: center; gap: 5px; margin-top: 7px;
	font: 500 10.5px var(--mono); color: var(--d-faint); text-transform: uppercase; letter-spacing: .06em;
}
.qg-tqr .qg-in { width: 54px; padding: 5px 6px; font-size: 12px; text-align: center; }
.qg-tqr i {
	display: block; font-style: normal; margin-top: 5px; line-height: 1.4;
	font-size: 10.5px; color: var(--d-faint);
}
.qg-tqr i.is-bad { color: #FF8E88; }
.qg-tqr .qg-check { margin-top: 7px; align-items: center; }
.qg-tqr .qg-check input { margin: 0; width: 14px; height: 14px; }
.qg-tqr .qg-check label { font-size: 11.5px; }
.qg-notneeded { font: 500 10.5px var(--mono); color: var(--d-faint); text-transform: uppercase; letter-spacing: .06em; line-height: 1.5; }
.qg-del {
	appearance: none; cursor: pointer; background: none; border: 0; color: var(--d-faint);
	padding: 5px; border-radius: 6px; line-height: 0;
}
.qg-del:hover { color: #FF8E88; background: rgba(180, 35, 31, .16); }
.qg-del svg { width: 15px; height: 15px; }
.qg-addwrap { position: relative; margin-top: 14px; }
.qg-pop {
	position: absolute; z-index: 40; top: calc(100% + 8px); left: 0; min-width: 264px;
	max-height: 340px; overflow-y: auto;
	background: #17132A; border: 1px solid var(--d-line-2); border-radius: var(--r);
	box-shadow: 0 22px 50px rgba(4, 2, 12, .6); padding: 8px; display: none;
}
.qg-pop.is-open { display: block; }
.qg-pop-k {
	font: 500 10.5px var(--mono); text-transform: uppercase; letter-spacing: .08em;
	color: var(--d-faint); padding: 8px 10px 6px; margin: 0;
}
.qg-pop-item {
	appearance: none; width: 100%; text-align: left; cursor: pointer; background: none; border: 0;
	color: var(--d-text); font: 500 13px var(--body); padding: 8px 10px; border-radius: 8px;
	display: flex; align-items: center; gap: 10px;
}
.qg-pop-item:hover { background: var(--ink-800); color: var(--d-head); }
.qg-pop-item svg { width: 15px; height: 15px; flex: none; color: var(--d-faint); }
.qg-pop-item small { color: var(--d-faint); font-size: 11px; margin-left: auto; font-family: var(--mono); }
.qg-pop-sep { height: 1px; background: var(--d-line); margin: 6px 4px; border: 0; }

.qg-empty {
	text-align: center; padding: 34px 20px; margin: 0; color: var(--d-faint); font-size: 13.5px;
	line-height: 1.6;
}
.qg-empty b { color: var(--d-muted); font-family: var(--mono); font-weight: 600; }

.qg-warn {
	margin: 14px 0 0; font-size: 13px; line-height: 1.6; color: #F5D9A8;
	background: rgba(180, 120, 20, .16); border: 1px solid rgba(180, 120, 20, .4);
	border-radius: var(--r-sm); padding: 11px 14px;
}

/* ---- toast / live region ---- */
.qg-live {
	margin: 14px 0 0; font: 500 12.5px var(--mono); color: var(--violet-l); min-height: 18px;
}

/* ==========================================================================
   Studio layout: every option on the left, the code itself pinned on the
   right. The code changes on every keystroke, so it has to stay in view while
   you work down a long column of controls - that is the whole point of the
   sticky column, and under 1080px it becomes a compact strip that sticks to
   the top of the viewport instead.
   ========================================================================== */
.qg-studio {
	display: grid; grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
	gap: 16px; align-items: start;
}
.qg-opts { min-width: 0; }
.qg-opts > * + * { margin-top: 16px; }
.qg-opts > .qg-cols-2 { margin-top: 16px; }

.qg-code { position: sticky; top: calc(var(--header-h) + 14px); min-width: 0; }
.qg-codebox { display: grid; gap: 14px; }
.qg-codemain { min-width: 0; }
.qg-codeside { display: grid; gap: 12px; min-width: 0; }
.qg-codeside .qg-stage-note { margin: 0; }
.qg-codeside .qg-btnrow { margin: 0; }

/* the compatibility verdict, sitting directly under the code it judges */
.qg-compat {
	display: flex; align-items: flex-start; gap: 9px; margin: 0;
	font: 500 12.5px var(--body); line-height: 1.5;
	border: 1px solid var(--d-line); border-radius: var(--r-sm);
	background: var(--ink-850); padding: 10px 12px; color: var(--d-muted);
}
.qg-compat::before {
	content: ''; width: 9px; height: 9px; border-radius: 50%; flex: none; margin-top: 4px;
	background: var(--green);
}
.qg-compat b { color: var(--d-head); font-weight: 600; display: block; }
.qg-compat.is-strict { border-color: color-mix(in srgb, var(--amber) 42%, transparent); }
.qg-compat.is-strict::before { background: var(--amber); }
.qg-compat.is-bad { border-color: rgba(180, 35, 31, .5); }
.qg-compat.is-bad::before { background: #FF8E88; }

/* ==========================================================================
   Design controls
   ========================================================================== */
.qg-sublab {
	font: 500 11.5px var(--body); color: var(--d-muted); margin: 0 0 8px;
}
.qg-sublab span { color: var(--d-faint); font-weight: 400; }

/* look presets: a real miniature code for each one, so nobody has to guess
   what "liquid" means */
.qg-presets { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.qg-preset {
	appearance: none; cursor: pointer; padding: 8px 6px 7px; text-align: center;
	background: var(--ink-900); border: 1px solid var(--d-line); border-radius: var(--r-sm);
	color: var(--d-muted); display: grid; gap: 6px; justify-items: center;
	transition: background .15s, border-color .15s, color .15s;
}
.qg-preset:hover { border-color: var(--d-line-2); background: var(--ink-800); color: var(--d-head); }
.qg-preset.is-on {
	background: color-mix(in srgb, var(--violet) 22%, var(--ink-850));
	border-color: color-mix(in srgb, var(--violet) 58%, transparent); color: var(--d-head);
}
.qg-preset i {
	display: block; width: 100%; max-width: 46px; aspect-ratio: 1; border-radius: 4px;
	background: #fff; overflow: hidden;
}
.qg-preset i svg { display: block; width: 100%; height: 100%; }
.qg-preset span { font: 500 11px var(--body); line-height: 1.2; }

/* shape rows: same miniature idea, cropped to the part being chosen */
.qg-shapes { display: flex; gap: 7px; flex-wrap: wrap; }
.qg-shape {
	appearance: none; cursor: pointer; padding: 6px 8px 5px; min-width: 62px;
	background: var(--ink-900); border: 1px solid var(--d-line); border-radius: var(--r-sm);
	color: var(--d-muted); display: grid; gap: 5px; justify-items: center;
	transition: background .15s, border-color .15s, color .15s;
}
.qg-shape:hover { border-color: var(--d-line-2); background: var(--ink-800); color: var(--d-head); }
.qg-shape.is-on {
	background: color-mix(in srgb, var(--violet) 22%, var(--ink-850));
	border-color: color-mix(in srgb, var(--violet) 58%, transparent); color: var(--d-head);
}
.qg-shape i {
	display: block; width: 34px; height: 34px; border-radius: 4px; background: #fff; overflow: hidden;
}
.qg-shape i svg { display: block; width: 100%; height: 100%; }
.qg-shape span { font: 500 10.5px var(--body); line-height: 1.15; white-space: nowrap; }
.qg-shape.is-risky i { box-shadow: inset 0 0 0 2px var(--amber); }

.qg-fixrow { margin-top: 12px; }

/* a plain segmented row, for choices that need no picture */
.qg-seg { display: flex; gap: 6px; flex-wrap: wrap; }
.qg-seg button {
	appearance: none; cursor: pointer; font: 500 12.5px var(--body);
	background: var(--ink-900); border: 1px solid var(--d-line); border-radius: 999px;
	color: var(--d-muted); padding: 8px 14px; transition: background .15s, border-color .15s, color .15s;
}
.qg-seg button:hover { border-color: var(--d-line-2); color: var(--d-head); }
.qg-seg button.is-on {
	background: color-mix(in srgb, var(--violet) 22%, var(--ink-850));
	border-color: color-mix(in srgb, var(--violet) 58%, transparent); color: var(--d-head);
}

/* ---- gradient ---- */
.qg-gradbox {
	margin-top: 12px; display: grid; gap: 12px;
	border-left: 2px solid var(--d-line-2); padding-left: 14px;
}
.qg-gradrow { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; }

.qg-slider {
	appearance: none; width: 100%; height: 22px; background: none; cursor: pointer; margin: 0;
}
.qg-slider::-webkit-slider-runnable-track {
	height: 4px; border-radius: 999px; background: var(--d-line-2);
}
.qg-slider::-webkit-slider-thumb {
	appearance: none; width: 16px; height: 16px; border-radius: 50%; background: var(--violet);
	border: 2px solid var(--ink-850); margin-top: -6px;
}
.qg-slider::-moz-range-track { height: 4px; border-radius: 999px; background: var(--d-line-2); }
.qg-slider::-moz-range-thumb {
	width: 16px; height: 16px; border: 2px solid var(--ink-850); border-radius: 50%;
	background: var(--violet);
}
.qg-slider:focus-visible { outline: 2px solid var(--violet); outline-offset: 3px; }

/* the ink read-out: the one number that decides whether a colour choice
   survives a laser printer and a phone in a dim room */
.qg-ink {
	margin: 12px 0 0; font: 500 12.5px var(--body); color: var(--d-muted); line-height: 1.5;
	display: flex; align-items: baseline; gap: 8px;
}
.qg-ink b { font-family: var(--mono); font-size: 12px; color: var(--d-head); }
.qg-ink.is-tight { color: var(--amber); }
.qg-ink.is-tight b { color: var(--amber); }
.qg-ink.is-bad { color: #FF8E88; }
.qg-ink.is-bad b { color: #FF8E88; }

/* ==========================================================================
   Logo
   ========================================================================== */
.qg-logo { display: grid; gap: 14px; }
.qg-drop {
	cursor: pointer; display: grid; justify-items: center; gap: 4px; text-align: center;
	border: 1px dashed var(--d-line-2); border-radius: var(--r-sm);
	background: var(--ink-900); padding: 20px 16px; color: var(--d-muted);
	transition: background .15s, border-color .15s;
}
.qg-drop:hover, .qg-drop:focus-visible, .qg-drop.is-over {
	border-color: color-mix(in srgb, var(--violet) 62%, transparent);
	background: color-mix(in srgb, var(--violet) 12%, var(--ink-900));
	outline: none;
}
.qg-drop svg { width: 22px; height: 22px; color: var(--d-faint); }
.qg-drop span { font: 500 12.5px var(--body); }
.qg-drop span b { color: var(--d-head); font-weight: 600; }
.qg-drop small { font-size: 11.5px; color: var(--d-faint); }

.qg-logo-have {
	display: flex; align-items: center; gap: 11px;
	background: var(--ink-900); border: 1px solid var(--d-line); border-radius: var(--r-sm);
	padding: 9px 11px;
}
.qg-logo-thumb {
	width: 34px; height: 34px; flex: none; border-radius: 6px; background: #fff;
	object-fit: contain; padding: 3px;
}
.qg-logo-name {
	font: 500 12.5px var(--body); color: var(--d-text); min-width: 0;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1 1 auto;
}
.qg-logo-opts { display: grid; gap: 13px; }
.qg-logo-opts .qg-field label span { font-family: var(--mono); font-size: 11.5px; }

.qg-verdict {
	margin: 0; font: 500 12.5px var(--body); line-height: 1.5; color: var(--d-muted);
	display: flex; align-items: flex-start; gap: 9px;
}
.qg-verdict::before {
	content: ''; width: 9px; height: 9px; border-radius: 50%; flex: none; margin-top: 4px;
	background: var(--green);
}
.qg-verdict.is-warn { color: var(--amber); }
.qg-verdict.is-warn::before { background: var(--amber); }
.qg-verdict.is-bad { color: #FF8E88; }
.qg-verdict.is-bad::before { background: #FF8E88; }

/* ==========================================================================
   Light sections below the board
   ========================================================================== */
.qg-cross { display: grid; grid-template-columns: 1fr 1fr; gap: 34px; align-items: start; }
.qg-deflist { margin: 16px 0 0; display: grid; gap: 12px; }
.qg-deflist > div { display: grid; grid-template-columns: 132px 1fr; gap: 16px; align-items: baseline; }
.qg-deflist dt { font: 600 12.5px var(--mono); color: var(--ink); margin: 0; }
.qg-deflist dd { margin: 0; font-size: 14px; color: var(--text); line-height: 1.6; }

.qg-tabletxt { width: 100%; border-collapse: collapse; margin-top: 18px; }
.qg-tabletxt th, .qg-tabletxt td {
	text-align: left; padding: 11px 14px; border-bottom: 1px solid var(--line); font-size: 14px;
}
.qg-tabletxt th {
	font: 500 10.5px var(--mono); text-transform: uppercase; letter-spacing: .08em;
	color: var(--muted); border-bottom-color: var(--line-2);
}
.qg-tabletxt td b { color: var(--ink); }
.qg-tabletxt tr:last-child td { border-bottom: 0; }

/* ==========================================================================
   Print pieces. Everything is laid out in real millimetres on an A4 page and
   printed by the browser - no PDF library, no server.
   ========================================================================== */
.qg-sheet { display: none; }

@media print {
	@page { size: A4 portrait; margin: 0; }

	/* Print ONLY the sheet. Live sites inject floating widgets (chat bubble,
	   cookie bar, scroll-to-top, accessibility button) as body-level fixed
	   elements that otherwise bleed into the PDF - hiding every body child
	   except the sheet kills all of them at once, whatever the plugin. */
	body > *:not(.qg-sheet) { display: none !important; }

	html, body { background: #fff !important; margin: 0 !important; padding: 0 !important; }

	.qg-sheet {
		display: block !important; color: #14121F; font-family: var(--body);
		width: 210mm;
	}
	.qg-sheet svg { display: block; }

	/* one printed page */
	.qg-pg {
		width: 210mm; height: 297mm; box-sizing: border-box; overflow: hidden;
		position: relative; break-after: page; page-break-after: always;
	}
	.qg-pg:last-child { break-after: auto; page-break-after: auto; }

	/* --- table tent: A4 folded across the middle into an A5 tent, so the
	   top half is printed upside down and reads correctly from the far side --- */
	.qg-tent-half {
		height: 148.5mm; box-sizing: border-box; padding: 16mm 18mm;
		display: flex; flex-direction: column; align-items: center; justify-content: center;
		text-align: center; gap: 6mm;
	}
	.qg-tent-half.is-flip { transform: rotate(180deg); }

	/* Fold marks, not fold instructions. Two short ticks in the outer margins
	   and nothing across the middle: whatever is printed here stays on the
	   paper forever, so the sheet must not carry a word of advice to itself. */
	.qg-fold { position: absolute; top: 148.5mm; left: 0; right: 0; height: 0; }
	.qg-fold::before, .qg-fold::after {
		content: ""; position: absolute; top: 0; width: 9mm; height: 0;
		border-top: 0.3mm solid #B8B8C4;
	}
	.qg-fold::before { left: 0; }
	.qg-fold::after { right: 0; }

	/* --- door sign: A4 portrait, one big code --- */
	.qg-door {
		height: 297mm; box-sizing: border-box; padding: 20mm 18mm 24mm;
		display: flex; flex-direction: column; align-items: center; justify-content: center;
		text-align: center; gap: 8mm;
	}

	/* --- badge / lanyard cards: 54 x 86 mm, nine to an A4 --- */
	.qg-badges {
		display: grid; grid-template-columns: repeat(3, 54mm); grid-auto-rows: 86mm;
		justify-content: center; align-content: start; gap: 4mm 6mm; padding: 12mm 0 0;
	}
	.qg-badge {
		box-sizing: border-box; border: 0.25mm dashed #C9C9D2; border-radius: 2mm;
		padding: 5mm 4mm; text-align: center;
		display: flex; flex-direction: column; align-items: center; justify-content: space-between;
		break-inside: avoid;
	}

	/* --- cut sheet: a grid of labelled codes with cut guides --- */
	.qg-cut {
		display: grid; justify-content: center; align-content: start;
		padding: 14mm 12mm; gap: 0;
	}
	.qg-cell {
		box-sizing: border-box; border: 0.25mm dashed #C9C9D2; padding: 5mm 3mm;
		text-align: center; display: flex; flex-direction: column; align-items: center; gap: 3mm;
		break-inside: avoid;
	}

	/* --- shared print typography ---
	   Every size is stated in points, never left to inherit. A visitor whose
	   browser default sits at 20px must get the same printed sheet as one at
	   16px, otherwise the labels wrap differently on their paper than on mine. */
	.qg-sheet { font-size: 10pt; line-height: 1.4; }
	.qg-p-head {
		font-family: var(--display); font-weight: 700; letter-spacing: -0.02em;
		margin: 0; line-height: 1.14; color: #14121F; font-size: 16pt;
	}
	.qg-p-sub { margin: 0; color: #4A4A5C; line-height: 1.4; font-size: 10.5pt; }
	.qg-p-lab {
		font-family: var(--mono); font-weight: 600; margin: 0; color: #14121F;
		line-height: 1.3; word-break: break-word; font-size: 9.5pt;
	}
	.qg-p-url {
		font-family: var(--mono); margin: 0; color: #74748A; word-break: break-all;
		line-height: 1.4; font-size: 8pt;
	}
	.qg-p-foot {
		font-family: var(--mono); font-size: 7pt; color: #9A9AA8; letter-spacing: .06em;
		text-transform: uppercase; margin: 0;
	}

	/* The printing note belongs to the SHEET, not to the pieces on it. It sits
	   in the bottom margin, outside every cut guide and every fold, so the
	   badge, the label and the tent come away carrying only the organizer's own
	   words - no measurements, no instructions, no tool name. */
	.qg-pgfoot {
		position: absolute; left: 12mm; right: 12mm; bottom: 5mm; margin: 0;
		font-family: var(--mono); font-size: 6.5pt; line-height: 1.35; color: #A8A8B4;
		text-align: center;
	}

	/* Sized per piece, because the reading distance is different for each: a
	   table tent is read from across a table, a badge from arm's length, a
	   door sign from the far end of a corridor, a cut label from the hand. */
	.qg-tent-half .qg-p-head { font-size: 24pt; }
	.qg-tent-half .qg-p-url { font-size: 12pt; }
	.qg-door .qg-p-head { font-size: 30pt; }
	.qg-door .qg-p-sub { font-size: 15pt; }
	.qg-door .qg-p-url { font-size: 13pt; }
	.qg-badge .qg-p-lab { font-size: 10pt; }
	.qg-badge .qg-p-url { font-size: 7.5pt; }
	.qg-cell .qg-p-lab { font-size: 9pt; }
	.qg-cell .qg-p-url { font-size: 7pt; }
	.qg-cell .qg-p-foot { font-size: 6pt; }
	.qg-sheet * { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
}

/* ==========================================================================
   Responsive
   ========================================================================== */
@media (max-width: 1080px) {
	/* minmax(0, 1fr) rather than 1fr, everywhere a grid collapses to one column.
	   A bare 1fr track is floored at the widest thing inside it, so one <pre> of
	   placement notes or one long link is enough to push the column - and with
	   it the page - wider than the screen. A zero floor lets the boxes that were
	   given their own scrollbars actually use them. */
	.qg-cols, .qg-cols-2 { grid-template-columns: minmax(0, 1fr); }
	.qg-cols-3 { grid-template-columns: minmax(0, 1fr); }
	.qg-cross { grid-template-columns: minmax(0, 1fr); gap: 26px; }

	/* One column, and the code becomes a compact strip that rides the top of
	   the viewport - still always visible, but no longer eating half the
	   screen on a narrow one. */
	.qg-studio { grid-template-columns: minmax(0, 1fr); }
	.qg-code {
		order: -1; top: var(--header-h); z-index: 6;
		background: var(--ink-900); border: 1px solid var(--d-line); border-radius: var(--r);
		padding: 12px; margin-bottom: 4px;
	}
	.qg-codebox { grid-template-columns: 128px minmax(0, 1fr); gap: 13px; align-items: start; }
	.qg-stage { min-height: 0; padding: 10px; }
	.qg-stage svg { max-width: 108px; }
	.qg-stage.is-empty { font-size: 11.5px; padding: 18px 8px; }
	.qg-codeside .qg-hint { display: none; }
	.qg-presets { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
	.qg-board-section { padding-top: 36px; }
	.qg-card { padding: 16px 15px; }
	.qg-tabs { width: 100%; }
	.qg-tab { flex: 1 1 auto; justify-content: center; padding: 9px 12px; font-size: 12.5px; }
	.qg-tab svg { display: none; }
	.qg-pair { grid-template-columns: minmax(0, 1fr); }
	.qg-deflist > div { grid-template-columns: minmax(0, 1fr); gap: 3px; }
	.qg-row { grid-template-columns: 74px minmax(0, 1fr); gap: 11px; }
	.qg-colorrow label { width: 68px; }
	.qg-presets { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.qg-gradrow { grid-template-columns: minmax(0, 1fr); }
	.qg-codebox { grid-template-columns: 96px minmax(0, 1fr); }
	.qg-stage svg { max-width: 80px; }
	.qg-codeside .qg-btnrow { gap: 6px; }
}

@media (prefers-reduced-motion: reduce) {
	.qg-btn, .qg-tab, .qg-type, .qg-size, .qg-level, .qg-piece,
	.qg-preset, .qg-shape, .qg-seg button, .qg-drop { transition: none; }
}

/* ==========================================================================
   Spacing helpers - last on purpose
   --------------------------------------------------------------------------
   Two one-line utilities so the template does not carry a dozen inline styles.
   They sit at the end of the file because they are single-class rules and the
   cascade decides ties by order: a component rule that writes the "margin"
   shorthand - ".qg-sublab { margin: 0 0 8px }" being the one that caught me -
   resets margin-top to zero if it comes later. From down here they win against
   every component above, which is the only thing that makes them dependable.
   Anything added below this block must not write a "margin" shorthand.
   ========================================================================== */
.qg-mt { margin-top: 12px; }
.qg-mt-l { margin-top: 16px; }
