/* =============================================================================
 * LJE designer skin v2 (issue #161, epic #145).
 *
 * Production stylesheet derived from docs/mockups/skin-v2.css (the approved
 * P2 mockup). Differences from the mockup file, per its README:
 *   - no :root token copy — tokens come from the letterjacket theme
 *   - no .lj-btn mirror — the theme ships the component
 *   - no mockup demo-object styles
 *   - production adjustments for the live Fabric <canvas> at the end
 * When iterating on layout, change the mockup first, then re-derive.
 * ========================================================================== */

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

/* --- Icon button ------------------------------------------------------------
 * Base .lje-icon-btn rules (box, border, hover/focus, disabled) live in the
 * shared lje-tools modal.css; this stylesheet declares 'lje-modal' as an
 * enqueue dependency, so only the designer-specific extensions live here. */

/* Stroke SVG icons (#282; module-scoped advance of #184) inherit the
 * button color so hover/pressed states keep working. */
.lje-icon-btn svg {
	width: 16px;
	height: 16px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.8;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* v2 active state: teal border + text on the active tint. primary-active
 * (#00747e) instead of primary keeps the letterforms AA on the tint. */
.lje-icon-btn[aria-pressed="true"] {
	border-color: var(--lj-color-primary);
	background: var(--lj-color-active-tint, #e6f6f7);
	color: var(--lj-color-primary-active);
}

/* --- Editor layout (v2 shell, #459) ------------------------------------------ */
/* The editor is no longer one bordered card: the root is a transparent frame
 * on the funnel-gray page and each region (toolbar / stage / inspector /
 * order bar) is its own white card. */
.lje-editor {
	background: transparent;
}

/* Designer page frame: gray funnel background, no page H1 — the toolbar owns
 * the product context. Scoped to the vendor's designer body class; this
 * stylesheet only loads on designer views anyway. */
body.wpd-customization-page { background: var(--lj-color-bg-funnel, #f7f7f6); }
body.wpd-customization-page .lj-entry__header { display: none; }

/* Same vertical rhythm as the funnel shell (theme _woocommerce.scss): a short
 * gap under the header, a long run of funnel bg before the footer. */
body.wpd-customization-page .lj-main {
	padding-block: clamp(1.5rem, 2vw, 2.5rem) clamp(5rem, 5vw, 6rem);
}

/* --- Toolbar card ------------------------------------------------------------- */
.lje-editor__topbar {
	display: flex;
	align-items: center;
	gap: var(--lj-space-5);
	padding: 0.6rem 1.1rem;
	background: var(--lj-color-bg);
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	flex-wrap: wrap;
	margin-bottom: var(--lj-space-4);
}

/* Back to the envelope: icon-only teal arrow (title/aria-label carry the text). */
.lje-editor__back {
	font-size: 1.1rem;
	font-weight: var(--lj-font-weight-medium, 600);
	color: var(--lj-color-primary);
	text-decoration: none;
	flex-shrink: 0;
}
.lje-editor__back:hover { color: var(--lj-color-primary-active, var(--lj-color-navy)); }

/* Product context: back + photo + title/meta block. Sized by its content, not
 * by a fixed share of the bar (#732): the old clamp(260px, 34%, 520px)
 * ellipsized the product name at about a third of the toolbar while the space
 * to its right sat empty. `flex: 1 1 0` is the shape that fixes it: a zero
 * flex-basis means this block never measures wider than the line and so can't
 * push the actions onto a second row, while flex-grow claims whatever the
 * actions leave. The name therefore shows in full at desktop widths and
 * min-width:0 keeps the ellipsis for when the space really runs out — long
 * catalog names, and small screens. */
.lje-topbar__context {
	display: flex;
	align-items: center;
	gap: 0.7rem;
	min-width: 0;
	flex: 1 1 0;
}

.lje-topbar__photo {
	width: 52px;
	height: 34px;
	object-fit: cover;
	border-radius: 3px;
	border: 1px solid var(--lj-color-divider, #ececea);
	flex-shrink: 0;
}

/* Glyph fallback when the product has no photo. */
.lje-topbar__context .lje-envelope-glyph {
	width: 52px;
	height: 34px;
}

.lje-topbar__spec { min-width: 0; }

.lje-topbar__titlerow {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	min-width: 0;
}

.lje-topbar__title {
	font-size: 0.8125rem;
	font-weight: var(--lj-font-weight-bold, 700);
	text-transform: uppercase;
	letter-spacing: 0.03em;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* The #192 change-envelope switch-mode action. Words, not a pencil
   (#696): the 13px icon read as decoration and customers never found
   it. Outlined so it is legible as a control next to the title, and
   flex-shrink:0 so the title ellipsizes before this label wraps.

   Lowercase since #799 (paired with the cart's "edit design" link,
   #774): display-only recasing — the PHP label stays sentence case and
   translatable ("Change envelope" in class-lje-skin-v2.php). */
.lje-topbar__change {
	display: inline-flex;
	align-items: center;
	border: 0;
	border-bottom: 1px dashed var(--lj-color-primary, #00a5b2);
	border-radius: 0;
	background: transparent;
	padding: 0 0 1px;
	color: var(--lj-color-primary, #00a5b2);
	font-size: 0.6875rem;
	font-weight: var(--lj-font-weight-bold, 700);
	text-transform: lowercase;
	letter-spacing: 0.03em;
	line-height: 1.4;
	white-space: nowrap;
	cursor: pointer;
	flex-shrink: 0;
}
.lje-topbar__change:hover,
.lje-topbar__change:focus-visible {
	color: var(--lj-color-primary-hover, #008a96);
	border-bottom-color: var(--lj-color-primary-hover, #008a96);
}

.lje-topbar__meta {
	display: flex;
	align-items: center;
	gap: 0.35rem;
	font-size: var(--lj-text-xs);
	color: var(--lj-color-text-muted);
	white-space: nowrap;
}

/* Qty/print switchers as editable inline values: teal dashed underline. Same
 * options/URLs as before #459 — the carry/session-bridge flow is unchanged. */
.lje-editor select.lje-topbar__select {
	appearance: none;
	-webkit-appearance: none;
	width: auto;
	max-width: 100%;
	border: 0;
	border-bottom: 1px dashed var(--lj-color-primary);
	border-radius: 0;
	padding: 0 12px 1px 0;
	/* stylelint-disable-next-line scale-unlimited/declaration-strict-value -- SVG data-URI: url() cannot reference CSS custom properties; %2300a5b2 mirrors --lj-color-primary */
	background: transparent url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'><path d='M1 1l4 4 4-4' fill='none' stroke='%2300a5b2' stroke-width='1.6'/></svg>") right center / 10px 6px no-repeat;
	font-family: inherit;
	font-size: var(--lj-text-xs);
	font-weight: var(--lj-font-weight-medium, 600);
	color: var(--lj-color-primary);
	cursor: pointer;
}

.lje-topbar__divider {
	width: 1px;
	align-self: stretch;
	background: var(--lj-color-divider, #ececea);
	flex-shrink: 0;
}

.lje-editor__actions {
	display: flex;
	align-items: center;
	gap: var(--lj-space-2);
	flex-shrink: 0;
	/* margin-left:auto moved to .lje-topbar__actions (#663 review): the
	 * action buttons and the history cluster sit together at the right
	 * edge — two auto margins would split the free space between them. */
}

/* History cluster: 34px squares; start-over signals destructive on hover. */
.lje-editor__actions .lje-icon-btn {
	width: 34px;
	height: 34px;
}
.lje-editor__actions .lje-icon-btn:disabled {
	opacity: 1;
	color: var(--lj-color-border-strong, #c9c9c4);
	border-color: var(--lj-color-border);
}
.lje-editor__actions .lje-icon-btn--danger:hover,
.lje-editor__actions .lje-icon-btn--danger:focus-visible {
	border-color: var(--lj-color-accent, #fb3640);
	color: var(--lj-color-accent, #fb3640);
}

/* (The Front/Back .lje-tabs retired with D2 — the side switcher is the canvas
 * minimap, .lje-minimap below.) */

/* --- Stage / canvas ------------------------------------------------------------ */
/* v2 editor grid (D2, matrix B-1; 320px sidebar track since D3, C-1): canvas
 * column + inspector column. The left column (canvas card + order-bar card)
 * is sticky so both stay in view while the inspector runs long. */
.lje-editor__body {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 320px;
	gap: var(--lj-space-4);
	align-items: start;
	min-height: 380px;
}

.lje-editor__main {
	display: flex;
	flex-direction: column;
	gap: var(--lj-space-4);
	position: sticky;
	/* Clear the WP toolbar when one is on screen (#832) — the canvas is the
	 * one thing that must never be clipped. The theme token is 0px for
	 * logged-out visitors, so their 16px gap is unchanged. */
	top: calc(var(--lj-admin-bar-h, var(--wp-admin--admin-bar--height, 0px)) + var(--lj-space-4, 1rem));
	min-width: 0;
}

/* Canvas card (matrix B-2): white 680px-tall card, light checkerboard. The
 * canvas fit recompute reads the stage width at boot (canvas_w contract,
 * #189) — the card only frames it. Taller-than-card canvases scroll (margin
 * auto on .lje-canvas keeps overflow-safe centering). */
.lje-stage {
	position: relative;
	/* The height is capped so the whole sticky column (stage + gap + order
	 * bar) always fits the viewport (#663). Without the cap the column is
	 * taller than a short viewport, and a sticky box taller than the viewport
	 * pins its top and leaves its bottom permanently below the fold — ADD TO
	 * CART became literally unreachable under ~840px of viewport, at any
	 * scroll position. The reserve covers the sticky top offset, the column
	 * gap and the order bar (which grows when the status line shows).
	 * Above that height nothing changes: the 680px card is unchanged on a
	 * normal desktop viewport. */
	height: min(680px, calc(100vh - 12rem));
	min-height: 380px;
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	overflow: hidden;
	display: flex;
	padding: var(--lj-space-6);
	background-color: var(--lj-color-bg, #fff);
	/* Checkerboard tile at the approved "marcada" tint (#663, v8 mock): the
	 * old #f4f4f2 read as plain white, and reading the stage as a work
	 * surface is part of the zoom story (#664) — the customer has to see
	 * there is room around the envelope. No token equivalent (see #327). */
	background-image:
		linear-gradient(45deg, #e2e2dd 25%, transparent 25%, transparent 75%, #e2e2dd 75%),
		linear-gradient(45deg, #e2e2dd 25%, transparent 25%, transparent 75%, #e2e2dd 75%);
	background-size: 24px 24px;
	background-position: 0 0, 12px 12px;
}

/*
 * In the mockup .lje-canvas was the white fake-envelope card (fixed #10
 * aspect-ratio + padding). In production it just hosts the live Fabric
 * canvas — the envelope artwork IS the canvas background image, sized by
 * the engine to the vendor-identical geometry. No frame, no aspect lock;
 * the paper-lift shadow wraps the canvas without touching its sizing.
 */
.lje-canvas {
	position: relative;
	width: fit-content;
	/* No max-width (#664): the element now scales with the zoom and may
	 * exceed the stage — the stage clips and pan navigates. A width cap
	 * would shrink the wrapper under its own canvas and detach the paper
	 * overlay from the envelope. The shadow lives on the paper box below. */
	margin: auto;
}

/* The envelope's own box (#664): inset comes from the editor's apron via the
 * skin JS, so this tracks the envelope exactly at every zoom. Shadow and
 * guides ride it; transparent face, so die-cut art keeps its silhouette. */
.lje-canvas__paper {
	position: absolute;
	pointer-events: none;
	box-shadow: 0 10px 30px rgba(50, 50, 44, 0.22);
}

/* Safe-area LEGEND (B-4, unparked in R1 #457; made a legend in #879): the
 * bottom-left white pill. It used to be a <label> wrapping a checkbox that
 * toggled the guides — the guides are always on now, so the pill only names
 * them. Same box, same font, same check; no pointer cursor and no hover
 * state, because there is nothing to activate. */
.lje-stage__hint {
	position: absolute;
	bottom: 0.9rem;
	left: var(--lj-space-4);
	z-index: 20;
	display: flex;
	align-items: center;
	gap: 0.45rem;
	padding: 0.25rem 0.6rem;
	background: color-mix(in srgb, var(--lj-color-bg, #fff) 85%, transparent);
	border-radius: var(--lj-radius-sm);
	font-size: 0.8rem;
	color: var(--lj-color-text-muted);
}

/* Stands in for the checked native checkbox this replaced (#879): the same
 * 13px box in the same accent teal with a white tick — drawn, so it is not a
 * control and cannot be focused, clicked or announced as one. */
.lje-stage__hint-mark {
	position: relative;
	flex: 0 0 auto;
	width: 13px;
	height: 13px;
	border-radius: 2px;
	background: var(--lj-color-primary, #00a5b2);
}

.lje-stage__hint-mark::after {
	content: "";
	position: absolute;
	top: 1px;
	left: 4px;
	width: 3px;
	height: 7px;
	border: solid var(--lj-color-bg, #fff);
	border-width: 0 2px 2px 0;
	transform: rotate(45deg);
}

/* Our safe-area overlay (R1): dashed teal inset on the envelope's own box.
 * Decorative only — pointer-events none, so drag/select/drop pass through;
 * the vendor art's baked-in guides stay visible underneath. */
/* Inside the paper box since #664, so the guides scale with the envelope
 * instead of sitting on the fixed element. Per-axis since #879: the inset is
 * 1/8 INCH on all four sides, which is a DIFFERENT percentage per axis for
 * the same physical distance — the skin JS sets both from the envelope's real
 * trim size on every art-box change. The single 3% below is the never-ran-JS
 * fallback only; it is the lopsided value #879 replaced (0.285in against
 * 0.124in on a #10), so it must never be the live path. */
.lje-canvas__guides {
	position: absolute;
	inset: var(--lje-safe-y, 3%) var(--lje-safe-x, 3%);
	z-index: 10;
	border: 1px dashed color-mix(in srgb, var(--lj-color-primary, #00a5b2) 55%, transparent);
	pointer-events: none;
}

/* Zoom pill (matrix B-8): white card, 26px borderless buttons, tabular label.
 * Stepping stays the engine's 25% + #189 auto zoom-out. */
.lje-stage__zoom {
	position: absolute;
	bottom: 0.9rem;
	right: var(--lj-space-4);
	z-index: 20;
	display: flex;
	align-items: center;
	gap: 0.2rem;
	padding: 0.15rem 0.3rem;
	background: var(--lj-color-bg);
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	color: var(--lj-color-text-muted);
}

.lje-stage__zoom .lje-icon-btn { width: 26px; height: 26px; border: 0; }

.lje-stage__zoom [data-lje="zoom-level"] {
	min-width: 44px;
	text-align: center;
	font-size: 0.8rem;
	font-variant-numeric: tabular-nums;
	color: var(--lj-color-text);
}

/* Whole-stage drop zone (#183 b): the stage itself accepts art drops. The
 * v2 cue (matrix B-7) is a tinted dashed overlay + centered card, revealed
 * by the same .is-dragover class the drop wiring already toggles. */
.lje-stage__dropcue {
	display: none;
	position: absolute;
	inset: 0;
	z-index: 30;
	align-items: center;
	justify-content: center;
	pointer-events: none;
	background: color-mix(in srgb, var(--lj-color-primary, #00a5b2) 8%, transparent);
	border: 2px dashed var(--lj-color-primary, #00a5b2);
	border-radius: var(--lj-radius-sm);
}

.lje-stage.is-dragover .lje-stage__dropcue { display: flex; }

/* Front/back minimap (matrix B-5; toolbar tabs A-8 retired into it): bottom-
 * center pill of 72px part thumbs. Since R1 (DEC-3 final, #457) each frame
 * hosts a live StaticCanvas render of that side's design (skin JS); the part
 * background art stays underneath as the base for empty parts and while a
 * render is in flight. The frame aspect comes from the real canvas ratio via
 * --lje-mini-aspect (inline, per product). */
.lje-minimap {
	position: absolute;
	left: 50%;
	transform: translateX(-50%);
	bottom: 0.9rem;
	z-index: 20;
	display: flex;
	gap: var(--lj-space-2);
	padding: 0.4rem 0.5rem;
	background: color-mix(in srgb, var(--lj-color-bg, #fff) 92%, transparent);
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
}

.lje-minimap__btn {
	border: 0;
	background: transparent;
	padding: 0;
	font-family: inherit;
	cursor: pointer;
}

.lje-minimap__frame {
	display: block;
	position: relative;
	overflow: hidden;
	width: 72px;
	aspect-ratio: var(--lje-mini-aspect, 8 / 5);
	background-color: var(--lj-color-bg, #fff);
	background-size: contain;
	background-position: center;
	background-repeat: no-repeat;
	border: 1px solid var(--lj-color-border);
	border-radius: 2px;
}

/* Live thumb canvas (R1, DEC-3): the StaticCanvas the skin drops into the
 * frame renders at 2x and scales down to fill it; the frame aspect equals
 * the canvas aspect, so no distortion. Never interactive. */
.lje-minimap__frame canvas {
	position: absolute;
	inset: 0;
	width: 100% !important;
	height: 100% !important;
	pointer-events: none;
}

.lje-minimap__btn[aria-selected="true"] .lje-minimap__frame {
	border: 2px solid var(--lj-color-primary);
}

.lje-minimap__label {
	display: block;
	margin-top: 2px;
	font-size: 0.6rem;
	letter-spacing: 0.06em;
	text-align: center;
	text-transform: uppercase;
	/* R1 (#457): muted, not faint — the prototype's faint step was ~2.8:1;
	 * muted keeps the inactive label AA-readable as text. */
	color: var(--lj-color-text-muted, #6b6b66);
}

.lje-minimap__btn[aria-selected="true"] .lje-minimap__label {
	color: var(--lj-color-primary);
	font-weight: var(--lj-font-weight-bold, 700);
}

/* Front-only print options (#179): the back thumb stays visible but locked —
 * clicking it opens the warning modal instead of switching faces. */
.lje-minimap__btn.is-locked {
	opacity: 0.5;
	cursor: not-allowed;
}

.lje-stage__dropcue > span {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	padding: 0.8rem 1.4rem;
	background: var(--lj-color-bg, #fff);
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	font-size: 0.9375rem;
	font-weight: 600;
	color: var(--lj-color-primary, #00a5b2);
	box-shadow: 0 6px 20px rgba(50, 50, 44, 0.18);
}

.lje-stage__dropcue svg {
	width: 20px;
	height: 20px;
	flex-shrink: 0;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.8;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.lje-stage.is-uploading::after {
	content: attr(data-lje-uploading);
	position: absolute;
	inset: 0;
	z-index: 6;
	display: flex;
	align-items: center;
	justify-content: center;
	background: rgba(255, 255, 255, 0.6);
	color: var(--lj-color-text);
	font-size: var(--lj-text-sm);
	font-weight: var(--lj-font-weight-medium);
	cursor: progress;
}

/* --- Inspector (three-card sidebar; two-card C-1 + the R1 Tips card) --------- */
/* The 264px bordered column became a transparent 320px track holding white
 * cards: the Tips card with the guidelines/file-type links (added R1, first
 * since R2a — #457), the tools card, and the contextual selection panel. */
.lje-inspector {
	display: flex;
	flex-direction: column;
	gap: var(--lj-space-3);
	min-width: 0;
}

/* (The has-selection order jump retired with #674: the selection status is a
 * FIXED slot now — "Nothing selected" + hint at rest, the tool panel when
 * something is selected — so the column order never changes and each
 * select/deselect breathes exactly one region. DOM order carries the
 * priority: Tips, status, uploads, Add.) */

.lje-inspector__tools,
.lje-inspector__section,
.lje-inspector__uploads,
.lje-inspector__tips {
	background: var(--lj-color-bg);
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	padding: 1rem 1.125rem;
}

/* Card headings: the static tools title and the live selection label share
 * the v2 card-title look. */
.lje-inspector__title,
.lje-inspector__label {
	display: block;
	font-size: var(--lj-text-sm);
	font-weight: var(--lj-font-weight-bold);
	letter-spacing: 0.03em;
	text-transform: uppercase;
	color: var(--lj-color-text);
}

.lje-inspector__title { margin-bottom: 0.7rem; }

/* Unified Add (#663): the two tiles that carry the usage sit on their own
 * row, the four shapes share the icon row below. */
.lje-inspector__add {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	gap: var(--lj-space-2);
}

.lje-inspector__shapes {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: var(--lj-space-2);
	margin-top: var(--lj-space-2);
}

/* Icon-only siblings of .lje-add-btn: same box, no label (the caption below
 * names all four at once instead of repeating a word under each icon). */
.lje-shape-btn {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 2.5rem;
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	background: var(--lj-color-bg);
	color: var(--lj-color-text);
	cursor: pointer;
}

.lje-shape-btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.lje-shape-btn:hover,
.lje-shape-btn:focus-visible { border-color: var(--lj-color-primary); color: var(--lj-color-primary-active); }

/* .lje-editor prefix: the theme's `.lj-prose p` rules (body-copy font-size and
 * margins) out-rank a lone class, so an unprefixed <p> silently renders at
 * prose scale — the same trap the proof-note hit in #457. */
.lje-editor .lje-inspector__shapes-cap {
	margin: 0.35rem 0 0;
	font-size: var(--lj-text-xs);
	color: var(--lj-color-text-muted);
	text-align: center;
}

.lje-add-btn {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.35rem;
	padding: 0.6rem 0.2rem;
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	background: var(--lj-color-bg);
	font-family: inherit;
	font-size: 0.75rem;
	color: var(--lj-color-text);
	cursor: pointer;
}

.lje-add-btn svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.lje-add-btn:hover,
.lje-add-btn:focus-visible { border-color: var(--lj-color-primary); color: var(--lj-color-primary-active); }

/* Envelope glyph: toolbar photo fallback (the #282 card/strip retired into
 * the toolbar context with #459). */
.lje-envelope-glyph {
	flex-shrink: 0;
	fill: color-mix(in srgb, var(--lj-color-primary) 6%, #fff);
	stroke: var(--lj-color-primary);
	stroke-width: 2;
}

/* Contextual panel card (C-4): the grid-stack below gives the stronger
 * stability guarantee than the prototype's min-height 220px — the tallest
 * panel fixes the card height across selection switches. */
.lje-inspector__section {
	display: flex;
	flex-direction: column;
	gap: var(--lj-space-3);
}

.lje-field { display: flex; flex-direction: column; gap: var(--lj-space-1); }

/* Panel help copy ("Nothing selected" hint, image-panel resize hint): R1
 * (#457) sizes it as quiet secondary text — it rendered at body copy scale
 * and outweighed the controls around it. .lje-editor prefix: the vendor page
 * renders through .lj-prose, whose `p` rules out-rank a lone class. */
.lje-editor .lje-inspector__hint {
	margin: 0;
	font-size: var(--lj-text-xs);
	line-height: 1.5;
	color: var(--lj-color-text-muted);
}

/* .lje-field__label covers non-<label> captions (the font combobox trigger
   is a <button> labelled via aria-labelledby, #181). */
.lje-field > label,
.lje-field > .lje-field__label {
	font-size: var(--lj-text-xs);
	/* Bold + ink (#664 QA round 8): the muted regular labels (Fill, Outline,
	 * Font...) read as placeholder text next to the controls they name. */
	font-weight: var(--lj-font-weight-bold, 700);
	color: var(--lj-color-text);
}

.lje-inspector select,
.lje-inspector input[type="text"],
.lje-inspector .lje-fontcb__trigger {
	width: 100%;
	padding: var(--lj-space-2);
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	font-family: inherit;
	font-size: var(--lj-text-sm);
	color: var(--lj-color-text);
	background: var(--lj-color-bg);
}

/* Size row (C-5): the label carries the live value ("Size — 30 pt"), the
 * range runs full width. 8–96 snapped to the typographic scale since R1
 * (DEC-2 final, #457).
 *
 * R2a (#457): the slider reads as kin to the primary button — border-gray
 * remainder, primary-teal fill and thumb, and on hover the same darkening
 * step the button takes (primary → primary-hover, on fill + thumb together).
 * WebKit has no fill pseudo, so the skin JS mirrors the thumb position into
 * --lje-size-fill and a hard-stop gradient paints the track; Firefox gets
 * the real ::-moz-range-progress. --lje-size-fill defaults to value 8 of
 * 0–13 (the 30 pt default) for the pre-JS paint. */
.lje-field input[type="range"] {
	--lje-size-fill: 61.54%;
	width: 100%;
	height: 16px; /* keep the hit/hover target thumb-sized, not track-sized */
	margin: 0;
	padding: 0;
	appearance: none;
	-webkit-appearance: none;
	background: transparent;
	cursor: pointer;
}

.lje-field input[type="range"]:focus-visible {
	outline: 2px solid var(--lj-color-primary, #00a5b2);
	outline-offset: 2px;
}

.lje-field input[type="range"]::-webkit-slider-runnable-track {
	height: 6px;
	border-radius: var(--lj-radius-pill, 9999px);
	background: linear-gradient(
		to right,
		var(--lj-color-primary, #00a5b2) 0%,
		var(--lj-color-primary, #00a5b2) var(--lje-size-fill),
		var(--lj-color-border, #e2e2e2) var(--lje-size-fill),
		var(--lj-color-border, #e2e2e2) 100%
	);
}

.lje-field input[type="range"]:hover::-webkit-slider-runnable-track {
	background: linear-gradient(
		to right,
		var(--lj-color-primary-hover, #008a96) 0%,
		var(--lj-color-primary-hover, #008a96) var(--lje-size-fill),
		var(--lj-color-border, #e2e2e2) var(--lje-size-fill),
		var(--lj-color-border, #e2e2e2) 100%
	);
}

.lje-field input[type="range"]::-webkit-slider-thumb {
	-webkit-appearance: none;
	appearance: none;
	width: 16px;
	height: 16px;
	margin-top: -5px; /* (16 − 6) / 2 — WebKit doesn't center the thumb */
	border: 0;
	border-radius: 50%;
	background: var(--lj-color-primary, #00a5b2);
}

.lje-field input[type="range"]:hover::-webkit-slider-thumb {
	background: var(--lj-color-primary-hover, #008a96);
}

.lje-field input[type="range"]::-moz-range-track {
	height: 6px;
	border-radius: var(--lj-radius-pill, 9999px);
	background: var(--lj-color-border, #e2e2e2);
}

.lje-field input[type="range"]::-moz-range-progress {
	height: 6px;
	border-radius: var(--lj-radius-pill, 9999px);
	background: var(--lj-color-primary, #00a5b2);
}

.lje-field input[type="range"]:hover::-moz-range-progress {
	background: var(--lj-color-primary-hover, #008a96);
}

.lje-field input[type="range"]::-moz-range-thumb {
	width: 16px;
	height: 16px;
	border: 0;
	border-radius: 50%;
	background: var(--lj-color-primary, #00a5b2);
}

.lje-field input[type="range"]:hover::-moz-range-thumb {
	background: var(--lj-color-primary-hover, #008a96);
}

.lje-field label output { font: inherit; color: inherit; }

/* B/I/U toggle squares (C-5; Underline promoted from the drawer). */
.lje-toggle-row { display: flex; gap: 0.4rem; }
.lje-toggle-row .lje-icon-btn { width: 34px; height: 34px; }

/* Align L/C/R as equal-width thirds (C-5; Align right promoted). */
.lje-align-row { display: flex; gap: 0.4rem; }
.lje-align-row .lje-icon-btn { flex: 1; width: auto; height: 34px; }

/* Swatches (C-7): the 8 most-used colors from 5.4 years of designs, as
 * 26px circles. The soft border keeps the white swatch visible; the active
 * ring below is the v2 pattern. Palette stays Pantone-locked. */
.lje-swatches {
	display: flex;
	flex-wrap: wrap;
	gap: 0.45rem;
}

.lje-swatch {
	width: 26px;
	height: 26px;
	border-radius: 50%;
	border: 1px solid rgba(0, 0, 0, 0.12);
	padding: 0;
	cursor: pointer;
}

.lje-swatch[aria-pressed="true"] {
	box-shadow: 0 0 0 2px var(--lj-color-bg), 0 0 0 4px var(--lj-color-primary);
}

.lje-color-inputs { display: flex; gap: var(--lj-space-2); }
.lje-color-inputs .lje-field { flex: 1; }

/* Image panel filename row (C-10): file icon + ellipsized name. Shown only
 * when a display name is known (.has-filename, set by refreshInspector);
 * otherwise the resize hint stands in. The image panel is never the grid-
 * stack's tallest, so the swap can't move the sidebar height. */
.lje-filename {
	display: none;
	align-items: center;
	gap: var(--lj-space-2);
	font-size: var(--lj-text-sm);
	color: var(--lj-color-text-muted);
	overflow: hidden;
	margin-bottom: var(--lj-space-3);
}

.lje-filename svg {
	width: 15px;
	height: 15px;
	flex-shrink: 0;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.6;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.lje-filename span {
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

[data-lje-panel="image"].has-filename .lje-filename { display: flex; }
[data-lje-panel="image"].has-filename .lje-inspector__hint { display: none; }

/* Shared action chips row (C-8): divider above, at the foot of every
 * selection panel. Delete is the red destructive chip. */
.lje-chips-row {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	margin-top: var(--lj-space-3);
	padding-top: var(--lj-space-3);
	border-top: 1px solid var(--lj-color-divider, #ececea);
}

.lje-chip-btn {
	font-size: 0.8rem;
	padding: 0.35rem 0.7rem;
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	background: var(--lj-color-bg);
	color: var(--lj-color-text);
	font-family: inherit;
	cursor: pointer;
}

.lje-chip-btn:hover,
.lje-chip-btn:focus-visible {
	border-color: var(--lj-color-primary);
	color: var(--lj-color-primary-active);
}

.lje-chip-btn--danger { color: var(--lj-color-accent, #fb3640); }
.lje-chip-btn--danger:hover,
.lje-chip-btn--danger:focus-visible {
	border-color: var(--lj-color-accent, #fb3640);
	color: var(--lj-color-accent-active, #b81f27);
}

/* --- Floating contextual bar (#663, the B piece) ----------------------------
 * The five object actions anchored to the live selection. On desktop it
 * REPLACES the in-panel chips row (hidden below, same commit — dropping the
 * commit restores the chips); on mobile the sheet keeps the chips and the
 * bar never displays. Lives inside .lje-canvas, whose origin matches the
 * canvas element, so the JS positions it in Fabric viewport pixels. */
.lje-ctxbar {
	display: none;
	position: absolute;
	z-index: 15; /* above the safe-area guides (10), below the stage pills (20) */
	align-items: center;
	gap: 0.2rem;
	padding: 0.25rem 0.3rem;
	background: var(--lj-color-bg);
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-md, 8px);
	box-shadow: 0 3px 12px rgba(50, 50, 44, 0.14);
	white-space: nowrap;
}

@media (min-width: 768px) {
	.lje-ctxbar:not([hidden]) { display: flex; }
	/* The bar replaces the chips on desktop — the panels stay content-only. */
	.lje-chips-row { display: none; }
}

.lje-ctxbar__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 30px;
	height: 30px;
	border: 0;
	border-radius: var(--lj-radius-sm);
	background: transparent;
	color: var(--lj-color-text);
	cursor: pointer;
}
.lje-ctxbar__btn svg {
	width: 15px;
	height: 15px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.7;
	stroke-linecap: round;
	stroke-linejoin: round;
}
.lje-ctxbar__btn:hover,
.lje-ctxbar__btn:focus-visible { background: var(--lj-color-surface, #f0f0ee); }
.lje-ctxbar__btn--danger { color: var(--lj-color-accent, #fb3640); }
.lje-ctxbar__btn--danger:hover,
.lje-ctxbar__btn--danger:focus-visible { color: var(--lj-color-accent-active, #b81f27); }

.lje-ctxbar__sep {
	width: 1px;
	height: 18px;
	background: var(--lj-color-divider, #ececea);
	margin: 0 0.15rem;
}

/* --- "Your uploads" tray (#180): session uploads as mini-thumbnails in
 * their own sidebar card under the tools card. Click inserts another
 * instance (no re-upload). A thumb whose file is not placed on any part
 * goes dashed + dimmed with the "Not on your design" badge below it — the
 * button's aria-label carries the same state for AT. --- */
/* .lje-editor prefix (#671): the theme's .lj-prose ul/li rules out-rank a
 * lone class — disc markers, 24px ul padding and an 8px li+li top margin
 * bled through as stray dots and misaligned thumbs. Same trap as the proof
 * note (#457) and the shapes caption (#663). */
.lje-editor .lje-uploads-list {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: var(--lj-space-2);
	margin: 0;
	padding: 0;
	list-style: none;
}

.lje-editor .lje-uploads-list li {
	display: block;
	list-style: none;
	margin: 0;
	padding: 0;
}

.lje-upload-thumb { min-width: 0; position: relative; }

/* Remove control (#675): overlaps the thumb's top-right corner, like the
 * fonts list's remove — instant, no confirm; the server file is untouched. */
.lje-editor .lje-upload-thumb__remove {
	position: absolute;
	top: -6px;
	right: -6px;
	z-index: 2;
	width: 18px;
	height: 18px;
	padding: 0;
	border: 1px solid var(--lj-color-border-strong, #c9c9c4);
	border-radius: 50%;
	background: var(--lj-color-bg);
	color: var(--lj-color-text-muted);
	font-size: 12px;
	line-height: 1;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
}
.lje-editor .lje-upload-thumb__remove:hover,
.lje-editor .lje-upload-thumb__remove:focus-visible {
	border-color: var(--lj-color-accent, #fb3640);
	color: var(--lj-color-accent, #fb3640);
}

.lje-upload-thumb__btn {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	aspect-ratio: 1;
	padding: 0.25rem;
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	background: var(--lj-color-bg);
	cursor: pointer;
}

.lje-upload-thumb__btn img {
	max-width: 100%;
	max-height: 100%;
	object-fit: contain;
}

.lje-upload-thumb__btn:hover,
.lje-upload-thumb__btn:focus-visible { border-color: var(--lj-color-primary); }

.lje-upload-thumb__state {
	display: none;
	margin-top: 0.2rem;
	font-size: 0.65rem;
	line-height: 1.25;
	text-align: center;
	color: var(--lj-color-text-muted, #6b6b66);
}

.lje-upload-thumb.is-unused .lje-upload-thumb__btn { border-style: dashed; }
.lje-upload-thumb.is-unused .lje-upload-thumb__btn img { opacity: 0.55; }
.lje-upload-thumb.is-unused .lje-upload-thumb__state { display: block; }

/* The vendor page renders the editor through the_content inside the theme's
 * .lj-prose scope, whose v2 accordion look for <details> (divider borders,
 * bold space-between summary, right chevron ::after, content margins) bleeds
 * into the module disclosures. Class-heavy selectors out-rank the prose rules
 * regardless of enqueue order. */
.lje-editor .lje-inspector details { border-top: 0; border-bottom: 0; }
.lje-editor .lje-inspector details > summary { padding: 0; }
.lje-editor .lje-inspector details > summary::after { content: none; }
.lje-editor .lje-inspector details > :not(summary) { margin: 0; max-width: none; }

/* (The "More tools" reveal retired with #663 — the four shapes now sit in one
 * visible row inside the tools card, so there is nothing left to disclose.) */

/* --- Order bar (own white card since #459; in the sticky left column since
 * #460 — the column gap owns the spacing; v2 internals #462) ---------------- */
.lje-orderbar {
	display: grid;
	/* instructions | fonts | CTA cell (status + ATC) */
	grid-template-columns: 1fr 1fr auto;
	gap: 1.25rem;
	align-items: end;
	padding: var(--lj-space-4) 1.125rem;
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	background: var(--lj-color-bg);
}

/* Captions (D-2): uppercase letter-spaced, still real <label for> elements. */
.lje-orderbar .lje-field { gap: 0.35rem; }
.lje-orderbar .lje-field > label {
	text-transform: uppercase;
	letter-spacing: 0.04em;
}

.lje-orderbar textarea {
	width: 100%;
	/* Same box height as .lje-attach (#663 review): with align-items:end on
	 * the grid, equal field heights are what line the two captions up. */
	min-height: 2.4rem;
	padding: 0.55rem 0.6rem;
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	font-family: inherit;
	font-size: var(--lj-text-sm);
	resize: vertical;
	outline-color: var(--lj-color-primary);
}

.lje-attach {
	display: flex;
	align-items: center;
	gap: var(--lj-space-2);
	padding: 0.55rem 0.75rem;
	/* Dashed in the shared field gray (#663 review round 2, Carlos): the ink
	 * border read heavier than every other field in the bar. The bold ink
	 * label keeps the affordance. */
	border: 1.5px dashed var(--lj-color-border-strong, #c9c9c4);
	border-radius: var(--lj-radius-sm);
	font-family: inherit;
	font-size: var(--lj-text-sm);
	font-weight: var(--lj-font-weight-bold, 700);
	color: var(--lj-color-text, #32322c);
	background: var(--lj-color-bg);
	cursor: pointer;
}

/* Hover invites the drop (prototype); the .is-dragover state below wins
 * while a file is actually over the field. */
.lje-attach:hover {
	border-color: var(--lj-color-primary);
	color: var(--lj-color-primary);
}

/* CTA cell (D-1/D-6): status stacks above the button, right-aligned; an
 * empty status has zero height, so the button keeps the grid end line. */
.lje-orderbar__cta {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	justify-content: flex-end;
	gap: var(--lj-space-1);
}

.lje-orderbar__status {
	font-size: var(--lj-text-xs);
	color: var(--lj-color-text-muted);
	text-align: right;
}

/* v2 CTA metrics on top of the theme primary (hover/active come with it). */
.lje-orderbar .lj-btn--primary {
	padding: 0.85rem 2rem;
	font-size: 0.9375rem;
	letter-spacing: 0.02em;
	white-space: nowrap;
}

.lje-attach svg {
	width: 14px;
	height: 14px;
	flex-shrink: 0;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.6;
	stroke-linecap: round;
	stroke-linejoin: round;
}

/* --- Mobile: inspector collapses to a bottom sheet (< md / 768px) ------------- */


/* --- Production adjustments (live Fabric canvas) --------------------------- */
/* The canvas keeps its native bitmap size (pointer math + vendor-identical
 * geometry). Overflow hidden since #664: when the zoomed element exceeds the
 * stage, pan navigates — scrollbars would fight the drag. */
.lje-canvas .canvas-container { margin: 0 auto; }
.lje-stage { overflow: hidden; }

/* Pan affordance (#664): the checkerboard invites the drag; fabric sets its
 * own cursors over the canvas (defaultCursor 'grab' on empty areas). */
.lje-stage { cursor: grab; }
.lje-stage.is-panning,
.lje-stage.is-panning * { cursor: grabbing; }

/* Off-screen font preloader (display:none would skip the font download). */
.lje-fonts-preloader {
	position: absolute;
	left: -9999px;
	top: 0;
	visibility: hidden;
	pointer-events: none;
}

/* --- Inspector stability + palette disclosure (P4 #162) --------------------- */
/* Grid-stack: all panels share one cell; the tallest defines the height, so
 * switching selection/tools never makes the editor jump. Inactive panels are
 * hidden via visibility (kept in flow) instead of display:none. */
/* Off panels leave the flow (#663): the section's height follows the ACTIVE
 * panel, per the v8 mock. The old grid-stack (all panels in one cell, tallest
 * fixes the height) kept the column from jumping, but Carlos unblocked that
 * once the order bar stopped depending on the sidebar height — and it left a
 * mostly-empty card towering under short panels. */
.lje-inspector__panels > [data-lje-panel].is-off { display: none; }

/* The "+" swatch (#664 QA round 8, replacing the More colors disclosure):
 * same circle as its siblings, dashed to read as a control, not a color.
 * When open it rotates to an x, so the same spot closes the set. */
.lje-swatch-more {
	width: 26px;
	height: 26px;
	border-radius: 50%;
	border: 1px dashed var(--lj-color-border-strong, #c9c9c4);
	background: var(--lj-color-bg);
	padding: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	color: var(--lj-color-text-muted);
	cursor: pointer;
}
.lje-swatch-more svg {
	width: 12px;
	height: 12px;
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	transition: transform 0.15s ease;
}
.lje-swatch-more:hover,
.lje-swatch-more:focus-visible {
	border-color: var(--lj-color-primary);
	color: var(--lj-color-primary-active);
}
.lje-swatch-more[aria-expanded="true"] svg { transform: rotate(45deg); }

.lje-swatches--more { margin-top: 0.45rem; }

@media (prefers-reduced-motion: reduce) {
	.lje-swatch-more svg { transition: none; }
}

/* Keep the panel's action rows inside the column. */
.lje-inspector .lje-toggle-row { flex-wrap: wrap; }

input[readonly][data-lje="hex"],
input[readonly][data-lje="pantone"] {
	background: var(--lj-color-surface);
	color: var(--lj-color-text-muted);
	cursor: default;
}

/* --- Print-ready artwork chips (order bar, P4 #162) ------------------------- */
/* The field's own gap (0.35rem, D-2) spaces the list; no extra margin. The
 * empty list stays in flow so the aria-live region keeps announcing. */
.lje-artwork-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--lj-space-1);
}

/* Empty list leaves the flow (#663 review): as a flex child it still claimed
 * a gap slot at zero height, making the fonts field 6px taller than the
 * instructions field — which is what knocked the two captions off one line. */
.lje-artwork-list:empty { display: none; }
.lje-artwork-list li {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--lj-space-2);
	padding: var(--lj-space-1) var(--lj-space-2);
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
	font-size: var(--lj-text-xs);
	color: var(--lj-color-text);
	overflow-wrap: anywhere;
}
.lje-artwork-remove {
	border: 0;
	background: transparent;
	color: var(--lj-color-text-muted);
	font-size: var(--lj-text-base);
	line-height: 1;
	cursor: pointer;
	padding: 0 var(--lj-space-1);
}
.lje-artwork-remove:hover { color: var(--lj-color-accent, #b21e27); }

/* --- a11y contrast (axe, P4 #162) ------------------------------------------- */
/* The back link went icon-only teal with #459: graphical control, 3:1 bar.
 * (The tab-contrast fix retired with the toolbar tabs — D2 minimap.) */

/* --- Upload-in-flight feedback (#183 a) -------------------------------------- */
@keyframes lje-uploading-pulse {
	50% { opacity: 0.45; }
}

.lje-add-btn.is-uploading,
.lje-attach.is-uploading,
.lje-inspector [data-lje="replace-btn"].is-uploading {
	animation: lje-uploading-pulse 1s ease-in-out infinite;
	cursor: progress;
}

/* --- Artwork field as drop target (#183 e) ----------------------------------- */
.lje-orderbar .lje-field.is-dragover .lje-attach {
	border-color: var(--lj-color-primary);
	border-style: solid;
	background: color-mix(in srgb, var(--lj-color-primary) 6%, #fff);
	color: var(--lj-color-text);
}

/* --- Wide breakout (#183 f; 1380px v2 shell #459) ----------------------------- */
/* The designer escapes the content column up to --lj-container-wide (1380px),
 * centered on the page. The canvas fit recompute reads the stage width at
 * boot, so the larger stage automatically yields a larger canvas (canvas_w
 * contract: designs save their actual width and every loader rescales). */
@media (min-width: 768px) {
	.lje-editor {
		width: min(var(--lj-container-wide, 1380px), calc(100vw - 48px));
		margin-inline: calc((100% - min(var(--lj-container-wide, 1380px), calc(100vw - 48px))) / 2);
	}
}

/* Modals (#179): the `.lje-modal*` component now lives in the shared lje-tools
 * utility (includes/utilities/modal/assets/css/modal.css), enqueued here via
 * lje_enqueue_modal_assets(). See #273. */

/* v2 modal shell deltas (E-1), scoped to the designer's dialogs per DEC-6 —
 * every builder in class-lje-skin-v2.php adds .lje-modal--designer, so other
 * lje-tools consumers of the shared utility keep their look. The shared css
 * already carries the v2 base (radius 4, 560px, ink scrim, uppercase header,
 * gray ✕, and the position:fixed/inset:0/margin:auto centering fix — which
 * these overrides never touch). */
.lje-modal--designer {
	/* Prototype paper shadow — warmer ink-based than the shared black. */
	box-shadow: 0 12px 40px rgba(50, 50, 44, 0.3);
}
.lje-modal--designer .lje-modal__header { padding: 14px 18px; }
.lje-modal--designer .lje-modal__body { padding: 16px 18px; }

/* Borderless gray ✕ per the prototype header; hover darkens to ink —
 * never red (red is reserved for destructive actions). */
.lje-modal--designer .lje-modal__header .lje-icon-btn {
	width: 30px;
	height: 30px;
	border: 0;
	font-size: 1.1rem;
	color: var(--lj-color-text-muted, #6b6b66);
}
.lje-modal--designer .lje-modal__header .lje-icon-btn:hover,
.lje-modal--designer .lje-modal__header .lje-icon-btn:focus-visible {
	color: var(--lj-color-text, #32322c);
}

/* Save modal (E-2): "DESIGN NAME" caption over a full-width input — the same
 * uppercase letter-spaced caption treatment as the order-bar labels (D-2),
 * still a real <label for>. Status line, maxlength, Enter-to-save and the
 * guest sign-in variant are untouched. */
.lje-modal--designer .lje-field > label {
	text-transform: uppercase;
	letter-spacing: 0.04em;
}
.lje-modal--designer .lje-field input[type="text"] {
	width: 100%;
	box-sizing: border-box;
	padding: 0.55rem 0.7rem;
	border: 1px solid var(--lj-color-border, #e2e2e2);
	border-radius: var(--lj-radius-sm, 4px);
	font-family: inherit;
	font-size: 0.9375rem;
	color: var(--lj-color-text, #32322c);
	background: var(--lj-color-bg, #fff);
	outline-color: var(--lj-color-primary, #00a5b2);
}

/* Toolbar actions (#663, replacing the .lje-topbar-link text links of #459):
 * these act and navigate, so they read as buttons. The dashed underline is
 * reserved for the controls that reveal a chooser (qty/print switchers, Tips).
 * Nothing here is filled — ADD TO CART is the designer's only filled teal
 * button, and a second one makes the CTA ambiguous. */
.lje-tbtn {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.4rem 0.7rem;
	border: 1px solid transparent;
	border-radius: var(--lj-radius-sm);
	background: transparent;
	font-family: inherit;
	font-size: var(--lj-text-sm);
	font-weight: var(--lj-font-weight-medium, 600);
	color: var(--lj-color-text-muted);
	white-space: nowrap;
	cursor: pointer;
}

.lje-tbtn svg {
	width: 15px;
	height: 15px;
	flex-shrink: 0;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.6;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.lje-tbtn:hover,
.lje-tbtn:focus-visible { background: var(--lj-color-surface, #f0f0ee); color: var(--lj-color-text); }

/* (The Save outline retired in review (#663): all three actions share the
 * ghost treatment, and the states below carry Save's feedback — the border
 * now only appears on the error state, where it is an alert.) */

/* Save states (#663). The width is locked to the widest label so the toolbar
 * does not shift as the label swaps; the transition is what makes "Saved"
 * fade back to "nothing to save" instead of blinking. */
.lje-tbtn--save {
	min-width: 9.5rem;
	justify-content: center;
	transition: background-color 0.28s ease, border-color 0.28s ease, color 0.28s ease;
}

/* Nothing to save: still focusable (aria-disabled, not [disabled]) so the
 * keyboard can reach it, but it stops inviting a click that would do
 * nothing. With the ghost base there is no border to remove, so the
 * disabled read comes from the lighter text — the same tone the disabled
 * history buttons use. */
.lje-tbtn--save.is-clean {
	color: var(--lj-color-border-strong, #c9c9c4);
	cursor: default;
}
.lje-tbtn--save.is-clean:hover,
.lje-tbtn--save.is-clean:focus-visible {
	background: transparent;
	color: var(--lj-color-border-strong, #c9c9c4);
}

/* Success, not teal: the filled teal belongs to ADD TO CART, and a second
 * filled teal button on screen makes the CTA ambiguous. */
.lje-tbtn--save.is-saved,
.lje-tbtn--save.is-saved:hover {
	background: var(--lj-color-success, #1c7c33);
	border-color: var(--lj-color-success, #1c7c33);
	color: var(--lj-color-bg, #fff);
}

.lje-tbtn--save.is-error,
.lje-tbtn--save.is-error:hover {
	background: transparent;
	border-color: var(--lj-color-danger, #721c24);
	color: var(--lj-color-danger, #721c24);
}

@media (prefers-reduced-motion: reduce) {
	.lje-tbtn--save { transition: none; }
}

.lje-topbar__actions {
	display: flex;
	align-items: center;
	gap: 0.25rem;
	/* Right-aligned with the history cluster right after (#663 review).
	 * flex-shrink:0 since #732: the context block now grows into the free
	 * space, and the actions must keep their intrinsic width rather than
	 * being squeezed by it. */
	margin-left: auto;
	flex-shrink: 0;
}

/* Mobile-only controls (#663): the toolbar kebab and the commerce-bar peek
 * exist in the DOM everywhere but only the <=767px block reveals them. */
.lje-topbar__more { display: none; }
.lje-orderbar__peek { display: none; }

.lje-orderbar__count {
	min-width: 1.15rem;
	padding: 0 0.3rem;
	border-radius: var(--lj-radius-pill, 9999px);
	background: var(--lj-color-primary-active, #00747e);
	color: var(--lj-color-text-inverse, #fff);
	font-size: 0.65rem;
	font-weight: var(--lj-font-weight-bold, 700);
	line-height: 1.5;
	text-align: center;
}

/* This divider carries meaning — everything past it leaves the current
 * design, where unsaved work is lost — so it reads stronger than the
 * structural divider that only separates toolbar groups. */
.lje-topbar__divider--actions {
	align-self: center;
	height: 1.4rem;
	margin: 0 0.35rem;
	background: var(--lj-color-border-strong, #c9c9c4);
}

/* Saved designs (#190): picker rows — v2 bordered cards (E-3) with the
 * stored thumb (single, labelled Front; dual thumbs parked E-4). The modal
 * status line (.lje-modal__status) lives in the shared modal utility (#273). */
.lje-designs-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
}
.lje-design-row {
	display: flex;
	align-items: center;
	gap: 0.9rem;
	padding: 0.6rem 0.75rem;
	border: 1px solid var(--lj-color-border);
	border-radius: var(--lj-radius-sm);
}
.lje-design-row__thumb { flex-shrink: 0; }
.lje-design-row__thumb img {
	display: block;
	width: 84px;
	height: auto;
	border: 1px solid var(--lj-color-border, #e2e2e2);
	border-radius: 2px;
	background: var(--lj-color-bg, #fff);
}
.lje-design-row__thumb span {
	display: block;
	margin-top: 2px;
	font-size: 0.6rem;
	color: var(--lj-color-text-muted, #6b6b66);
	text-align: center;
	text-transform: uppercase;
	letter-spacing: 0.06em;
}
.lje-design-row__meta {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
	flex: 1;
}
.lje-design-row__meta strong {
	font-size: 0.9375rem;
	font-weight: 600;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.lje-design-row__meta span {
	font-size: var(--lj-text-xs);
	color: var(--lj-color-text-muted);
}
.lje-design-row__actions {
	display: flex;
	gap: 0.4rem;
	flex-shrink: 0;
}

/* Row actions (E-3): quiet bordered buttons, colored label — Load teal
 * (AA-safe primary-active, same as the toolbar links), Delete red (the D3
 * danger-chip pattern; red stays reserved for destructive actions). */
.lje-design-row__btn {
	padding: 0.35rem 0.8rem;
	border: 1px solid var(--lj-color-border, #e2e2e2);
	border-radius: var(--lj-radius-sm, 4px);
	background: var(--lj-color-bg, #fff);
	font-family: inherit;
	font-size: 0.8rem;
	font-weight: 600;
	cursor: pointer;
}
.lje-design-row__btn--load { color: var(--lj-color-primary-active, #00747e); }
.lje-design-row__btn--load:hover,
.lje-design-row__btn--load:focus-visible { border-color: var(--lj-color-primary, #00a5b2); }
.lje-design-row__btn--danger { color: var(--lj-color-accent, #fb3640); }
.lje-design-row__btn--danger:hover,
.lje-design-row__btn--danger:focus-visible {
	border-color: var(--lj-color-accent, #fb3640);
	color: var(--lj-color-accent-active, #b81f27);
}

/* Tips card links (#663): reference material closing the sidebar, so they
 * read as two compact inline links rather than the full-width navy ghost
 * buttons of R2a (#457) — at that weight they competed with the tools that
 * actually build the design. They join the "reveals something" tier with the
 * qty/print switchers: teal + dashed underline. Both keep their modals.
 * .lje-editor prefix: the theme's .lj-prose ul rules (disc markers, padding)
 * out-rank a lone class — same bleed as the module <details> shield. */
.lje-editor .lje-tips-links {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.35rem 0.5rem;
}

/* One-line card (#663 review, v8 mock): the TIPS label sits inline with its
 * two links instead of stacking a heading over them. */
.lje-inspector__tips { display: flex; align-items: center; gap: 0.6rem; }
.lje-inspector__tips .lje-inspector__title { margin-bottom: 0; }
.lje-editor .lje-tips-links li { list-style: none; margin: 0; }

/* Separator between the two links, so they read as one line of references. */
.lje-editor .lje-tips-links li + li::before {
	content: "\00b7";
	margin-right: 0.35rem;
	color: var(--lj-color-text-muted);
}

.lje-editor .lje-tips-link {
	display: inline;
	border: 0;
	padding: 0;
	background: transparent;
	font-family: inherit;
	font-size: var(--lj-text-xs);
	font-weight: var(--lj-font-weight-medium, 600);
	line-height: 1.4;
	color: var(--lj-color-primary-active, #00747e);
	text-decoration: underline;
	text-decoration-style: dashed;
	text-decoration-thickness: 1px;
	text-underline-offset: 3px;
	cursor: pointer;
}
.lje-editor .lje-tips-link:hover { color: var(--lj-color-primary-hover, #008a96); }
.lje-editor .lje-tips-link:focus-visible {
	outline: 2px solid var(--lj-color-primary-active, #00747e);
	outline-offset: 2px;
}

/* Guidelines content: rule statement + can-do/don't-do examples per row */
.lje-guidelines__row {
	display: grid;
	grid-template-columns: 1fr 1fr 1fr;
	gap: var(--lj-space-4);
	align-items: start;
}
.lje-guidelines__rule { margin: 0; }
.lje-guidelines__example { margin: 0; }
.lje-guidelines__example img { width: 100%; height: auto; display: block; margin-bottom: var(--lj-space-2); }
.lje-guidelines__example figcaption { font-size: var(--lj-text-xs); color: var(--lj-color-text-muted); }
.lje-guidelines__example figcaption strong { color: var(--lj-color-text); }

.lje-guidelines__pricing {
	margin-top: var(--lj-space-4);
	padding: var(--lj-space-4);
	border-radius: var(--lj-radius-sm);
	/* stylelint-disable-next-line scale-unlimited/declaration-strict-value -- legacy cream highlight carried with the DEC-4 guidelines content; no --lj-* token (the old --ast-global-color-6 var no longer exists — this was its fallback value). */
	background: #edeadc;
}
.lje-guidelines__pricing h3 { margin: 0 0 var(--lj-space-2); font-size: var(--lj-text-sm); }
.lje-guidelines__pricing p { margin: 0; }

@media (max-width: 767px) {
	.lje-guidelines__row { grid-template-columns: 1fr; }
}

/* --- Envelope switch (#192) -------------------------------------------------- */
/* The entry point is the envelope card's head (pencil) since #282. */

/* Consolidated switch-review modal: one section per applicable change. */
.lje-review-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--lj-space-3, 0.75rem);
}
.lje-review-item {
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding-bottom: var(--lj-space-3, 0.75rem);
	border-bottom: 1px solid var(--lj-color-border, #e2e2e2);
}
.lje-review-item:last-child { border-bottom: 0; padding-bottom: 0; }
.lje-review-item__head {
	font-weight: var(--lj-font-weight-bold, 700);
	color: var(--lj-color-text, #32322c);
}
.lje-review-item__body {
	font-size: var(--lj-text-sm, 0.875rem);
	color: var(--lj-color-text-muted, #6b6b66);
	line-height: var(--lj-leading-normal, 1.55);
}

/* --- Boot loading state (#170; card layout since #459) ------------------------ */
/* A cohesive skeleton of the editor layout (toolbar card + canvas card +
 * sidebar card) covers the real editor until the canvas is interactive — it
 * blocks premature tool use (Fabric isn't ready yet) without an opaque "just
 * a moment" curtain. markReady() drops .is-booting to reveal the editor. */
.lje-boot { display: none; }
.lje-editor.is-booting { position: relative; }
.lje-editor.is-booting .lje-boot {
	display: flex;
	flex-direction: column;
	gap: var(--lj-space-4, 1rem);
	position: absolute;
	inset: 0;
	z-index: 5;
	background: var(--lj-color-bg-funnel, #f7f7f6);
}

/* Screen-reader-only status; the visual skeleton is aria-hidden. */
.lje-boot__status {
	position: absolute;
	width: 1px; height: 1px;
	margin: -1px; padding: 0; border: 0;
	overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

.lje-boot__topbar,
.lje-boot__inspector,
.lje-boot__canvas {
	background: var(--lj-color-bg, #fff);
	border: 1px solid var(--lj-color-border, #e2e2e2);
	border-radius: var(--lj-radius-sm, 4px);
}

.lje-boot__topbar {
	display: flex;
	align-items: center;
	gap: var(--lj-space-3, 0.75rem);
	padding: 0.6rem 1.1rem;
}
.lje-boot__topbar > .lje-boot__bar--photo { margin-right: var(--lj-space-1, 0.25rem); }
.lje-boot__topbar > .lje-boot__bar:nth-child(2) { margin-right: auto; }

.lje-boot__body { flex: 1; display: flex; gap: var(--lj-space-4, 1rem); min-height: 0; }
.lje-boot__canvas { flex: 1; }
.lje-boot__inspector {
	width: 320px;
	flex-shrink: 0;
	padding: var(--lj-space-4, 1rem);
	display: flex;
	flex-direction: column;
	gap: var(--lj-space-4, 1rem);
}

.lje-boot__bar,
.lje-boot__canvas {
	background: linear-gradient(100deg, #e6e8ea 38%, #f3f5f6 50%, #e6e8ea 62%);
	background-size: 220% 100%;
	animation: lje-boot-shimmer 1.25s ease-in-out infinite;
}
.lje-boot__bar { height: 14px; border-radius: var(--lj-radius-pill, 9999px); }
.lje-boot__bar--pill { width: 72px; height: 34px; border-radius: var(--lj-radius-sm, 4px); }
.lje-boot__bar--photo { width: 52px; height: 34px; flex-shrink: 0; border-radius: 3px; }
.lje-boot__bar--short { width: 60%; }
@keyframes lje-boot-shimmer { to { background-position: -220% 0; } }

.lje-editor.is-ready { animation: lje-canvas-in 0.25s ease both; }
@keyframes lje-canvas-in { from { opacity: 0; } to { opacity: 1; } }

@media (max-width: 767px) {
	.lje-boot__body { flex-direction: column; }
	.lje-boot__canvas { min-height: 260px; }
	.lje-boot__inspector { width: auto; }
}

@media (prefers-reduced-motion: reduce) {
	.lje-boot__bar,
	.lje-boot__canvas { animation: none; }
	.lje-editor.is-ready { animation: none; }
}

/* Not-a-proof notice (#295) — liability wording, keep visible on the stage.
 * R1 (#457): back to the compact pre-D2 metrics (the 520px pill wrapped the
 * copy into a tall block that read oversized), dressed as the theme's soft
 * notice — R2b (#457): the site-standard soft-notice tokens (cream box from
 * the approved review-pay mock, _tokens-deferred.scss), muted xs copy.
 * .lje-editor prefix: the theme's .lj-prose `p` rules (body-copy font-size
 * and margins) out-rank a lone class — the pill silently rendered at prose
 * scale, which is what made it read oversized. */
.lje-editor .lje-stage__proof-note {
	position: absolute;
	top: var(--lj-space-3);
	left: 50%;
	transform: translateX(-50%);
	z-index: 20;
	max-width: 90%;
	margin: 0;
	padding: var(--lj-space-1) var(--lj-space-3);
	font-size: var(--lj-text-xs);
	line-height: 1.35;
	text-align: center;
	/* Ink, not muted grey (#663, Carlos): this is liability wording Karen
	 * asked to keep as a banner, so it has to read as a statement rather
	 * than as a caption. The cream/amber notice box is unchanged. */
	color: var(--lj-color-text, #32322c);
	background: var(--lj-color-notice-soft-bg, #fff8e6);
	border: 1px solid var(--lj-color-notice-soft-border, #e8d9a0);
	border-radius: var(--lj-radius-sm);
}

/* ≤768 fix (R1, flagged in D6): at exactly 768px the desktop grid squeezes
 * the canvas column and the absolute pill covered the canvas. Flow the note
 * above the canvas instead — the stage goes column so the static note can't
 * sit beside the canvas (the D1 regression this breakpoint used to have). */
@media (max-width: 768px) {
	/* Bottom padding keeps the canvas clear of the overlay pills; hint and
	 * zoom lift to a second row — all three don't fit beside the minimap on
	 * a narrow stage (true at exactly 768 too, where the desktop grid still
	 * applies — ex-mobile-block rules widened by 1px in R1). */
	.lje-stage { padding: var(--lj-space-4); padding-bottom: 9rem; height: auto; min-height: 320px; flex-direction: column; }
	.lje-stage__hint,
	.lje-stage__zoom { bottom: 5.5rem; }
	.lje-canvas { width: 100%; }
	.lje-editor .lje-stage__proof-note { position: static; transform: none; order: -1; max-width: 100%; margin: 0 0 var(--lj-space-2); }
}

/* Mobile overrides live at the end of the sheet on purpose (#663): several
 * base rules (the toolbar buttons, the peek button) were appended after the
 * old position of this block, and at equal specificity source order decides —
 * anything mobile must out-order everything base. */
@media (max-width: 767px) {
	/* The sticky left column dissolves (display: contents); the inspector and
	 * the order bar leave the flow entirely (#663): sheet + commerce bar pin
	 * to the bottom of the viewport, so the tools are always at hand and the
	 * canvas keeps the rest of the screen. */
	.lje-editor__body {
		display: flex;
		flex-direction: column;
		min-height: 0;
		/* Clearance so the stage bottom can scroll clear of the fixed
		 * sheet + commerce bar. */
		padding-bottom: 40vh;
	}
	.lje-editor__main { display: contents; }

	/* (The stage/pill narrow-viewport rules live in the ≤768px block with the
	 * proof-note flow fix — same collision at exactly 768, R1 #457.) */

	/* --- Contextual bottom sheet (#663, v8 mock). One sheet, two states:
	 * nothing selected -> Add tools + uploads tray + Tips; something selected
	 * -> the content panel only (its chips row carries the object actions).
	 * The has-selection class the desktop order rule uses drives this too. */
	.lje-inspector {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 3.4rem; /* the commerce bar's slim row */
		z-index: 890;   /* under the commerce bar, both under --lj-z-modal */
		max-height: 38vh;
		overflow-y: auto;
		width: 100%;
		padding: var(--lj-space-3) var(--lj-space-4) var(--lj-space-4);
		background: var(--lj-color-bg);
		border-radius: var(--lj-radius-md) var(--lj-radius-md) 0 0;
		box-shadow: 0 -3px 12px rgba(0, 0, 0, 0.08);
	}

	.lje-inspector .lje-inspector__section { display: none; }
	.lje-inspector.has-selection .lje-inspector__section { display: block; order: 0; }
	.lje-inspector.has-selection .lje-inspector__tools,
	.lje-inspector.has-selection .lje-inspector__uploads,
	.lje-inspector.has-selection .lje-inspector__tips { display: none; }

	/* The sheet keeps its own priority (#674): tools first at rest — the
	 * desktop DOM now leads with Tips, which would eat the sheet's prime
	 * space. The site-wide mobile pass owns the final word. */
	.lje-inspector .lje-inspector__tools { order: 1; }
	.lje-inspector .lje-inspector__uploads { order: 2; }
	.lje-inspector .lje-inspector__tips { order: 3; }

	/* Grab handle communicates the sheet affordance */
	.lje-inspector::before {
		content: "";
		display: block;
		width: 40px;
		height: 4px;
		margin: 0 auto;
		border-radius: 2px;
		background: var(--lj-color-surface);
	}

	/* --- Toolbar: the three action buttons fold into the kebab dropdown. --- */
	.lje-editor__topbar { position: relative; gap: var(--lj-space-2) var(--lj-space-3); }
	.lje-topbar__context { flex-basis: 100%; max-width: 100%; }
	.lje-topbar__meta { flex-wrap: wrap; white-space: normal; }
	.lje-topbar__divider { display: none; }
	.lje-editor__actions { margin-left: 0; flex: 1; justify-content: flex-start; }
	.lje-topbar__more { display: inline-flex; width: 34px; height: 34px; margin-left: auto; }

	.lje-topbar__actions { display: none; }
	.lje-topbar__actions.is-open {
		display: flex;
		flex-direction: column;
		align-items: stretch;
		position: absolute;
		top: calc(100% + 0.25rem);
		right: 0;
		z-index: 890;
		padding: 0.35rem;
		background: var(--lj-color-bg);
		border: 1px solid var(--lj-color-border);
		border-radius: var(--lj-radius-sm);
		box-shadow: 0 6px 18px rgba(50, 50, 44, 0.15);
	}
	/* The meaningful divider (past it you leave the design) turns horizontal. */
	.lje-topbar__actions.is-open .lje-topbar__divider--actions {
		display: block;
		width: auto;
		height: 1px;
		margin: 0.3rem 0.2rem;
	}
	.lje-topbar__actions.is-open .lje-tbtn { justify-content: flex-start; }

	/* --- Commerce bar (#663, v8 mock): slim fixed row — peek + CTA. The two
	 * fields stay in the DOM and unfold above the row via is-open, so the
	 * instructions/fonts plumbing (#186/#224 POST keys) is untouched. --- */
	.lje-orderbar {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 0;
		z-index: 900;
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: var(--lj-space-2) var(--lj-space-3);
		margin: 0;
		padding: 0.45rem var(--lj-space-4);
		border-radius: 0;
		border-left: 0;
		border-right: 0;
		border-bottom: 0;
		box-shadow: 0 -3px 12px rgba(0, 0, 0, 0.1);
	}
	.lje-orderbar__peek {
		display: inline-flex;
		align-items: center;
		gap: 0.4rem;
		border: 1px dashed var(--lj-color-border-strong, #c9c9c4);
		border-radius: var(--lj-radius-sm);
		padding: 0.45rem 0.6rem;
		background: var(--lj-color-bg);
		font-family: inherit;
		font-size: var(--lj-text-xs);
		font-weight: var(--lj-font-weight-medium, 600);
		color: var(--lj-color-text);
		cursor: pointer;
	}
	.lje-orderbar__peek svg {
		width: 13px;
		height: 13px;
		fill: none;
		stroke: currentColor;
		stroke-width: 1.6;
		stroke-linecap: round;
		stroke-linejoin: round;
	}
	.lje-orderbar > .lje-field { display: none; }
	.lje-orderbar.is-open > .lje-field { display: block; flex: 1 1 100%; }
	.lje-orderbar__cta { flex: 1; align-items: stretch; margin-left: auto; }
	.lje-orderbar .lj-btn { width: 100%; padding: 0.7rem 1rem; }
}
