/* ============================================================================
   Branding editor (брандиране) — storefront personalization module.

   Fonts: text stamps use Iskar Bold (UPPERCASE), number stamps use SpainEuro2016.
   Both are served locally from webroot/fonts/ as .ttf (see @font-face below), so
   they render for every customer, not just machines that have the font installed.
   The font-family stacks below keep sane fallbacks if a file is ever missing.

   Design: light cards on a soft background with one accent colour. Every colour,
   radius and shadow is a token on .branding-editor — change --br-accent in one
   place and the whole editor follows. The accent is the storefront's own blue
   (#00adee, see .buy / .size-chart in style.css) so the editor doesn't introduce
   a second brand blue.
   ============================================================================ */

@font-face {
	font-family: 'IskarBold';
	src: url('../fonts/iskar-bold.ttf?v=1') format('truetype');
	font-weight: 700;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: 'SpainEuro2016';
	src: url('../fonts/spaineuro2016.ttf?v=1') format('truetype');
	font-weight: 700;
	font-style: normal;
	font-display: swap;
}

.is-hidden { display: none !important; }

/* ---- design tokens ------------------------------------------------------ */
.branding-editor {
	--br-accent:      #00adee;
	--br-accent-dark: #0093c9;
	--br-accent-soft: #e8f7fd;
	--br-ink:    #16232e;   /* headings */
	--br-text:   #405365;   /* body copy */
	--br-muted:  #8a9bab;   /* labels, hints */
	--br-line:   #e4eaf0;   /* card borders, dividers */
	--br-line-2: #cfd9e3;   /* input borders, slider rail */
	--br-page:   #f6f8fa;
	--br-card:   #ffffff;
	--br-ok:     #1a9d5c;
	--br-danger: #d64545;
	--br-r:      12px;      /* card radius */
	--br-r-sm:   8px;       /* control radius */
	--br-shadow: 0 1px 2px rgba(16, 35, 54, .05), 0 6px 16px rgba(16, 35, 54, .05);

	max-width: 1180px;
	margin: 0 auto;
	padding: 14px 15px 28px;
	color: var(--br-text);
	font-size: 14px;
	line-height: 1.5;
}
.branding-editor h1 {
	margin: 0 0 12px;
	font-size: 20px;
	font-weight: 700;
	color: var(--br-ink);
	text-align: center;
	line-height: 1.3;
}
/* the editor runs on a bare layout with no site stylesheet, so the product link
   restates the storefront's own link treatment (#00adee, underlined). */
.branding-editor h1 a {
	color: var(--br-accent);
	text-decoration: underline;
}
.branding-editor h1 a:hover,
.branding-editor h1 a:focus { color: var(--br-accent-dark); text-decoration: underline; }

.branding-grid { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-start; }
/* The design stays put while the controls scroll past it.
   --br-sticky-top is measured at runtime (syncStickyOffset in branding-editor.js):
   the storefront pins a stack of bars to the viewport top — info strip + header +
   menu, 154px wide-screen but only 80px at tablet — and a hardcoded offset would
   park the preview underneath them at one breakpoint or leave a gap at another.

   The max-width keeps the whole preview inside that remaining space on short
   screens. It caps the WIDTH, not the height, on purpose: .branding-side is a
   fixed 3/4 box and stamp positions are stored as percentages of it, so changing
   its aspect would move every saved stamp relative to the garment. Narrowing the
   column scales box, image and stamps together and keeps the geometry honest. */
.branding-col-preview  {
	flex: 1 1 340px; min-width: 300px;
	position: sticky; top: var(--br-sticky-top, 12px);
	max-width: calc((100vh - var(--br-sticky-top, 12px) - 12px) * 3 / 4);
}
.branding-col-controls { flex: 1 1 460px; min-width: 300px; }

/* ---- preview ------------------------------------------------------------ */
.branding-previews { display: block; }
.branding-side {
	position: relative;
	background: var(--br-card);
	border: 1px solid var(--br-line);
	border-radius: var(--br-r);
	box-shadow: var(--br-shadow);
	overflow: hidden;
	aspect-ratio: 3 / 4;
}
/* one image at a time: only the active side's preview is shown (the side picker
   switches it). Stamp sizes are measured off the visible layer, so a hidden side
   MUST stay display:none — see scaleStamps() in branding-editor.js. */
.branding-previews .branding-side { display: none; }
.branding-previews .branding-side.active-side { display: block; }

.branding-side .side-label {
	position: absolute; top: 10px; left: 10px; z-index: 3;
	padding: 4px 10px; border-radius: 999px;
	background: var(--br-accent); color: #fff;
	font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
}
.branding-side .side-img { width: 100%; height: 100%; object-fit: contain; display: block; }
.branding-side .side-img.missing { display: none; }
.branding-side .no-img {
	position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
	color: var(--br-muted); font-size: 13px; text-align: center; padding: 20px;
}

/* the interactive overlay that holds stamps, sized exactly over the image */
.stamp-layer { position: absolute; inset: 0; z-index: 2; pointer-events: none; }

/* a rendered stamp on the preview — draggable + resizable */
.stamp-render {
	position: absolute; transform: translate(-50%, -50%);
	white-space: nowrap; line-height: 1; z-index: 2;
	pointer-events: auto; cursor: move; touch-action: none;
	user-select: none; -webkit-user-select: none;
	text-shadow: 0 0 2px rgba(0, 0, 0, .15);
}
.stamp-render.sel { outline: 2px dashed var(--br-accent); outline-offset: 5px; }
.stamp-handle {
	position: absolute; right: -10px; bottom: -10px; width: 17px; height: 17px;
	background: var(--br-accent); border: 2px solid #fff; border-radius: 50%;
	box-shadow: 0 1px 4px rgba(0, 0, 0, .35);
	cursor: nwse-resize; touch-action: none; font-size: 0; display: none;
}
.stamp-render.sel .stamp-handle { display: block; }
/* stamp colour is applied inline in JS (any CSS colour name or #hex), so no
   per-colour classes are needed here — white/black are no longer special. */
/* line-height 1.49 here, not the 1 the other stamps use: IskarBold draws its glyphs at
   1.485x its em box - measured, 60px of ink for a 40px font-size - so at line-height 1
   the letters overflowed their own element by ~10px top and bottom. The selection
   outline follows that element, so the dashed frame cut through the text and the resize
   handle sat inside it instead of at its corner. Half-leading splits evenly, so the box
   grows around the glyphs and the stamp itself does not move: the position is stored as
   pos_x/pos_y percentages, and drag/resize read those, never the box height. */
.stamp-render.font-text   { font-family: 'IskarBold', 'Iskar Bold', 'Iskar', 'Arial Black', sans-serif; text-transform: uppercase; font-weight: 700; line-height: 1.49; }
.stamp-render.font-number { font-family: 'SpainEuro2016', 'Spain Euro 2016', 'SpainEuro', 'Arial Narrow', sans-serif; font-weight: 700; }
.stamp-render.font-logo   { font-family: Arial, sans-serif; font-weight: 700; border: 2px solid currentColor; padding: 2px 6px; border-radius: 3px; font-size: 12px; }
/* logo stamps rendered as real images */
.stamp-render.has-logo { border: none; padding: 0; text-shadow: none; }
.stamp-logo-img { display: block; max-width: none; height: auto; pointer-events: none; }

/* ---- section cards ------------------------------------------------------ */
.branding-box {
	background: var(--br-card);
	border: 1px solid var(--br-line);
	border-radius: var(--br-r);
	box-shadow: var(--br-shadow);
	padding: 14px;
	margin-bottom: 11px;
}
.branding-box h2 {
	margin: 0 0 10px;
	font-size: 13px;
	font-weight: 700;
	letter-spacing: .06em;
	text-transform: uppercase;
	color: var(--br-ink);
}

/* ---- side picker -------------------------------------------------------- */
.side-picker { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
/* the second copy sits under the preview image: centred on it, and the
   margin flips to the top since nothing follows it in that column */
.side-picker-under { justify-content: center; margin: 10px 0 0; }
.side-picker-label { font-size: 13px; color: var(--br-muted); margin-right: 2px; }
.side-pick-btn {
	border: 1px solid var(--br-line-2); background: var(--br-card); color: var(--br-text);
	border-radius: var(--br-r-sm); padding: 7px 15px; cursor: pointer;
	font-size: 13px; font-weight: 600; font-family: inherit;
	transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.side-pick-btn:hover { border-color: var(--br-accent); color: var(--br-accent); }
.side-pick-btn.active {
	background: var(--br-accent); border-color: var(--br-accent); color: #fff;
	box-shadow: 0 2px 8px rgba(0, 173, 238, .3);
}

/* ---- stamp palette ------------------------------------------------------ */
.stamp-palette { display: flex; flex-wrap: wrap; gap: 10px 8px; }
.stamp-palette button {
	position: relative;
	display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
	border: 1px solid var(--br-line-2); background: var(--br-card); color: var(--br-text);
	border-radius: var(--br-r-sm); padding: 6px 11px; cursor: pointer;
	font-size: 13px; font-weight: 600; font-family: inherit; line-height: 1.25;
	text-align: left;
	transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.stamp-palette button:hover {
	background: var(--br-accent-soft); border-color: var(--br-accent); color: var(--br-accent-dark);
}
/* what this stamp adds to ONE piece — see priceLabel() in branding-editor.js */
.stamp-palette .pal-price { font-size: 11px; font-weight: 700; color: var(--br-accent-dark); }
.stamp-palette button:hover .pal-price { color: var(--br-accent-dark); }
/* how many of this stamp are already placed. The white ring lifts it off the
   pill so it reads as a notification badge rather than part of the label. */
.stamp-palette button.has-stamp { border-color: var(--br-accent); }
.stamp-palette .pal-badge {
	position: absolute; top: -6px; right: -6px;
	box-sizing: border-box; min-width: 19px; height: 19px; padding: 0 5px;
	display: flex; align-items: center; justify-content: center;
	border-radius: 999px; border: 2px solid var(--br-card);
	background: var(--br-accent); color: #fff;
	font-size: 11px; font-weight: 700; line-height: 1;
	box-shadow: 0 1px 3px rgba(16, 35, 54, .2);
}

/* ---- placed stamps ------------------------------------------------------ */
.stamp-list { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.stamp-list:empty { margin-top: 0; }
.stamp-item {
	border: 1px solid var(--br-line);
	border-radius: 10px;
	background: var(--br-card);
	padding: 7px 9px;
}
/* The box matching the stamp currently picked on the image. Border plus a soft accent
   ring - the same treatment .roster-table input:focus already uses - rather than a
   tinted background, which would swallow the accent-soft price pill sitting inside it.
   The image side marks the same stamp with .stamp-render.sel. */
.stamp-item.is-selected {
	border-color: var(--br-accent);
	box-shadow: 0 0 0 3px rgba(0, 173, 238, .15);
}
.stamp-item .stamp-head { display: flex; align-items: center; gap: 8px; }
.stamp-item .stamp-heading { display: flex; flex: 1 1 auto; align-items: baseline; flex-wrap: wrap; gap: 2px 8px; min-width: 0; }
.stamp-item .stamp-title { font-weight: 700; font-size: 14px; color: var(--br-ink); }
.stamp-item .stamp-side { font-size: 11px; font-weight: 500; color: var(--br-muted); white-space: nowrap; }
.stamp-item .stamp-side b { font-weight: 700; color: var(--br-text); }
.stamp-item .stamp-color { display: inline-flex; flex: 0 0 auto; align-items: center; gap: 6px; }
.stamp-item .stamp-color-label { font-size: 11px; font-weight: 600; color: var(--br-muted); }
.stamp-item .stamp-price {
	flex: 0 0 auto; padding: 3px 8px; border-radius: 999px;
	background: var(--br-accent-soft); color: var(--br-accent-dark);
	font-size: 11px; font-weight: 700; white-space: nowrap;
}
/* Admin only: the price pill becomes editable. It keeps the pill's shape and
   colours so the card does not change character - only the number is live. */
.stamp-item .stamp-price-edit { display: inline-flex; align-items: center; gap: 3px; padding: 2px 6px; }
.stamp-item .stamp-price-edit input[type="number"] {
	width: 62px; padding: 1px 2px; margin: 0;
	border: 0; border-bottom: 1px dashed var(--br-accent-dark); border-radius: 0;
	background: transparent; text-align: right;
	font-family: inherit; font-size: 11px; font-weight: 700; color: var(--br-accent-dark);
	-moz-appearance: textfield;
}
.stamp-item .stamp-price-edit input[type="number"]::-webkit-outer-spin-button,
.stamp-item .stamp-price-edit input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.stamp-item .stamp-price-edit input[type="number"]:focus { outline: none; background: #fff; }
.stamp-item .stamp-price-edit em { font-style: normal; font-size: 11px; font-weight: 700; }

/* "remove this stamp" reads as a bare × until it is boxed — give it a real
   button face (border + fill) so it remains an obvious compact hit target. */
.stamp-item .stamp-remove {
	flex: 0 0 auto; width: 30px; height: 30px; padding: 0;
	display: flex; align-items: center; justify-content: center;
	border: 1px solid var(--br-line-2); border-radius: var(--br-r-sm);
	background: var(--br-card);
	color: var(--br-muted); line-height: 1; font-family: inherit;
	cursor: pointer;
	transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
/* The × is an inline SVG rather than a typed "&times;". Exo 2 paints U+00D7 on
   the maths axis below the em-box centre — so a text
   glyph can never sit centred here, and it would shift again if the webfont
   failed to load. A drawn cross is symmetric about its own box by definition. */
.stamp-item .stamp-remove svg { display: block; width: 16px; height: 16px; }
.stamp-item .stamp-remove:hover {
	background: #fdecec; border-color: var(--br-danger); color: var(--br-danger);
}
.stamp-item .stamp-remove:active { background: #f9dcdc; }

.stamp-fields { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: flex-start; margin-top: 7px; }
.stamp-fields label {
	display: flex; flex-direction: column; gap: 6px;
	font-size: 12px; font-weight: 600; color: var(--br-muted);
	letter-spacing: .01em;
}

/* logo variant select */
.stamp-fields select {
	-webkit-appearance: none; appearance: none;
	padding: 8px 28px 8px 11px;
	border: 1px solid var(--br-line-2); border-radius: var(--br-r-sm);
	background-color: var(--br-card);
	/* chevron drawn as an inline SVG so no image file is needed */
	background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='none' stroke='%238a9bab' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round' d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
	background-repeat: no-repeat; background-position: right 10px center;
	font-size: 13px; font-weight: 600; color: var(--br-text); font-family: inherit;
	cursor: pointer;
}
.stamp-fields select:focus { outline: none; border-color: var(--br-accent); box-shadow: 0 0 0 3px rgba(0, 173, 238, .15); }
.stamp-fields select.s-variant { max-width: 210px; }

/* colour swatches */
.color-swatches { display: inline-flex; gap: 8px; align-items: center; }
/* swatch background is set inline to the actual colour (see JS); the grey border
   keeps light colours (e.g. white) visible against the card. */
.color-swatch {
	width: 26px; height: 26px; border-radius: 50%;
	border: 1px solid var(--br-line-2); cursor: pointer;
	transition: box-shadow .15s ease, transform .1s ease;
}
.color-swatch:hover { transform: scale(1.08); }
.color-swatch.sel { box-shadow: 0 0 0 2px #fff inset, 0 0 0 2px var(--br-accent); border-color: var(--br-accent); }

/* "Any colour" picker - admin only. A native colour input renders as a chunky OS
   button; stripping that chrome lets it read as one more swatch in the row. The
   dashed border is this module's cue for "you supply this" (cf. the file input). */
.color-swatches .s-color-any {
	width: 26px; height: 26px; padding: 0;
	border: 1px dashed var(--br-line-2); border-radius: 50%;
	background: none; cursor: pointer;
	-webkit-appearance: none; -moz-appearance: none; appearance: none;
	transition: box-shadow .15s ease, transform .1s ease;
}
.color-swatches .s-color-any:hover { transform: scale(1.08); }
.color-swatches .s-color-any:focus {
	outline: none; border-color: var(--br-accent);
	box-shadow: 0 0 0 3px rgba(0, 173, 238, .15);
}
/* the inner swatch is what actually paints the colour - let it fill the circle */
.color-swatches .s-color-any::-webkit-color-swatch-wrapper { padding: 0; }
.color-swatches .s-color-any::-webkit-color-swatch { border: 0; border-radius: 50%; }
.color-swatches .s-color-any::-moz-color-swatch { border: 0; border-radius: 50%; }

/* file input (customer / admin logo upload) */
.stamp-fields input[type="file"] {
	max-width: 210px; font-size: 12px; color: var(--br-muted);
	padding: 7px; border: 1px dashed var(--br-line-2); border-radius: var(--br-r-sm);
	background: #fbfcfd; cursor: pointer;
}
.stamp-fields input[type="file"]::-webkit-file-upload-button {
	margin-right: 8px; padding: 5px 10px; border: 0; border-radius: 5px;
	background: var(--br-accent-soft); color: var(--br-accent-dark);
	font-weight: 700; font-size: 12px; font-family: inherit; cursor: pointer;
}
/* scoped to .stamp-fields so it outranks the label rule above without !important */
.stamp-fields .perpiece-hint {
	flex: 1 1 100%;
	font-weight: 500; font-style: italic;
	color: var(--br-muted);
}

/* ---- sizes & quantities -------------------------------------------------- */
/* Two columns of "size + stepper". Pushing the stepper to the far right of its
   column (space-between) put it closer to the NEXT column's size label than to
   its own, so the pairing had to be read twice. Each pair now sits in its own
   boxed row and the stepper follows the label immediately; the label's
   min-width keeps the steppers aligned down the column anyway. */
.size-rows { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 14px; }
.size-row {
	display: flex; align-items: center; flex-wrap: wrap; gap: 6px 9px; min-width: 0;
	padding: 3px 8px;
	border: 1px solid var(--br-line); border-radius: var(--br-r-sm);
	background: #fbfcfd;
}
.size-row .size-name {
	flex: 0 1 auto; min-width: 38px; max-width: 108px;
	font-weight: 700; font-size: 14px; color: var(--br-ink); line-height: 1.25;
}
/* the stock note (e.g. "23.5 cm/UK 4.5") drops to its own line so a long one
   cannot shove the stepper away from the size it belongs to */
.size-row .size-stock {
	display: block;
	color: var(--br-muted); font-size: 10px; font-weight: 400; line-height: 1.3;
	white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* − [ 0 ] + stepper. The number input stays a real input (typing still works and
   the editor listens for `input` on it); the buttons only nudge its value. */
.size-stepper {
	display: inline-flex; align-items: center; flex: 0 0 auto;
	border: 1px solid var(--br-line-2); border-radius: var(--br-r-sm);
	overflow: hidden; background: var(--br-card);
}
.size-step {
	width: 30px; height: 30px; padding: 0; border: 0; background: transparent;
	color: var(--br-accent); font-size: 17px; font-weight: 700; line-height: 1;
	font-family: inherit; cursor: pointer;
	transition: background-color .15s ease;
}
.size-step:hover { background: var(--br-accent-soft); }
.size-step:active { background: #d7effa; }
.size-row input[type="number"] {
	width: 42px; height: 30px; padding: 0; margin: 0;
	border: 0; border-left: 1px solid var(--br-line); border-right: 1px solid var(--br-line);
	border-radius: 0; text-align: center;
	font-size: 14px; font-weight: 700; color: var(--br-ink); font-family: inherit;
	background: var(--br-card);
	-moz-appearance: textfield;
}
.size-row input[type="number"]::-webkit-outer-spin-button,
.size-row input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.size-row input[type="number"]:focus { outline: none; background: var(--br-accent-soft); }

/* A size the saved design still orders but the shop no longer stocks. It stays
   on screen on purpose — removing it would silently change what the customer
   chose — so it is dimmed and labelled instead, with a one-click way out. */
.size-row.is-out { background: #fdf3f3; border-color: #f0d2d2; }
.size-row.is-out .size-name { color: var(--br-danger); }
/* wider than a size code like "S", so the name must not shrink below it */
.size-row.is-out .size-name { min-width: 62px; }
.size-row .size-out {
	display: block; white-space: nowrap;
	color: var(--br-danger); font-size: 10px; font-weight: 700; line-height: 1.3;
	text-transform: uppercase; letter-spacing: .04em;
}
.size-row .size-clear {
	flex: 0 0 auto; margin-left: auto; padding: 5px 9px;
	border: 1px solid #e7bcbc; border-radius: var(--br-r-sm);
	background: var(--br-card); color: var(--br-danger);
	font-size: 11px; font-weight: 700; font-family: inherit; cursor: pointer;
	transition: background-color .15s ease, border-color .15s ease;
}
.size-row .size-clear:hover { background: #fdecec; border-color: var(--br-danger); }

/* why the cart button is disabled — shown only when a sold-out size is ordered */
.branding-blocked {
	display: flex; align-items: flex-start; gap: 10px;
	margin-top: 11px; padding: 11px 13px;
	border: 1px solid #f0c9c9; border-left: 3px solid var(--br-danger);
	border-radius: var(--br-r-sm);
	background: #fdf3f3; color: #8d3232;
	font-size: 13px; line-height: 1.45;
}
.branding-blocked svg { flex: 0 0 auto; width: 18px; height: 18px; margin-top: 1px; color: var(--br-danger); }
.branding-blocked b { color: var(--br-danger); }
/* operators are warned, never blocked — the order already exists, and this
   screen is where they resolve it. Amber says "look at this", not "stop". */
.branding-blocked.is-warning {
	border-color: #f0dcae; border-left-color: #c98a00;
	background: #fff8e6; color: #7a5a00;
}
.branding-blocked.is-warning svg,
.branding-blocked.is-warning b { color: #a8730a; }

/* ---- roster -------------------------------------------------------------- */
.roster-scroll { overflow-x: auto; }
.roster-table { width: 100%; border-collapse: separate; border-spacing: 0 4px; }
.roster-table th {
	padding: 0 8px 4px; text-align: left;
	font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
	color: var(--br-muted); white-space: nowrap;
}
.roster-table th small { font-weight: 400; text-transform: none; letter-spacing: 0; color: var(--br-line-2); }
.roster-table td { padding: 0 8px; font-size: 13px; color: var(--br-text); vertical-align: middle; }
.roster-table td:first-child { font-weight: 700; color: var(--br-ink); }
.roster-table input {
	width: 100%; box-sizing: border-box; min-width: 90px;
	padding: 7px 10px; border: 1px solid var(--br-line-2); border-radius: var(--br-r-sm);
	font-size: 13px; font-family: inherit; color: var(--br-ink);
	text-transform: uppercase; background: var(--br-card);
	transition: border-color .15s ease, box-shadow .15s ease;
}
.roster-table input.roster-number { text-transform: none; }
/* Size groups have to read as blocks - 3xXS, then 2xS, then 4xM - not as one
   long list with a hairline in it. Three things do that together: real space
   above a new group, a rule with enough weight to hold the two apart, and the
   size stated once in ink at the top of the group with the repeats dimmed, so
   the eye lands on where a group begins instead of re-reading the same label.
   .roster-table is border-collapse: separate, where a border on a <tr> is never
   painted - it has to go on the cells. */
.roster-table tr.size-break td {
	position: relative;
	padding-top: 20px;
}
/* The rule must sit MIDWAY between the two groups it divides. As a border-top it could
   not: the space above it is fixed at the table's 4px border-spacing while the space
   below it is this cell's padding - measured 4px above vs 20px below, so it read as
   underlining the previous row rather than separating two blocks.
   Drawn as an absolutely positioned line it can go anywhere in that gap: top:7px from
   the cell gives 4 + 7 = 11px above and 20 - 7 - 2 = 11px below. The row keeps its old
   height exactly - 4 + 20 is the same 24px as the old 4 + 2 + 18. */
.roster-table tr.size-break td::before {
	content: '';
	position: absolute;
	top: 7px; left: 0; right: 0;
	border-top: 2px solid var(--br-line-2);
}
/* the group's opening row states the size; the rest of the group repeats it
   quietly so the column still answers "which size am I on?" when scrolled */
.roster-table tbody tr:not(.size-first) td:first-child {
	font-weight: 400; color: var(--br-muted);
}

/* the per-piece price column — right-aligned like a figure, never wrapping */
.roster-table .roster-price { text-align: right; white-space: nowrap; }
.roster-table td.roster-price { font-weight: 700; color: var(--br-ink); }
.roster-table input:focus {
	outline: none; border-color: var(--br-accent);
	box-shadow: 0 0 0 3px rgba(0, 173, 238, .15);
}

/* ---- roster: padlock + required validation -------------------------------
   The padlock sits inside the cell next to its input so the pair reads as one
   control. Locking means "this piece does not get this stamp": the value is
   cleared, the field goes inert and piecePrice() stops charging for it — which
   is how one piece (the coach's shirt) skips a stamp the rest of the order
   carries. Unlocking hands back an empty, required field. */
.roster-cell-wrap { display: flex; align-items: center; gap: 6px; }
.roster-cell-wrap input { flex: 1 1 auto; }

/* ⚠ Scoped to .roster-cell (0,2,0) on purpose. style.css carries a global
   `button, button:focus { outline: none; border: 0px; display: inline-block }`,
   and `button:focus` (0,1,1) outranks a bare `.roster-lock` (0,1,0). So the
   moment the button took focus - i.e. the instant you clicked it - it lost its
   border AND its flex centring, and the padlock jumped 8px to the left edge.
   Keeping every state at (0,2,0) leaves these rules in charge throughout. */
.roster-cell .roster-lock {
	flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
	width: 32px; height: 32px; padding: 0; cursor: pointer;
	border: 1px solid var(--br-line-2); border-radius: var(--br-r-sm);
	background: var(--br-card); color: var(--br-muted);
	transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.roster-cell .roster-lock svg { width: 16px; height: 16px; display: block; }
/* restated rather than inherited: :focus is exactly where the global rule bites */
.roster-cell .roster-lock:hover,
.roster-cell .roster-lock:focus {
	display: inline-flex; border: 1px solid var(--br-accent);
	color: var(--br-accent); outline: none;
}

/* locked: the field is visibly out of play and the padlock becomes the one lit
   control in the cell, because it is the only way back. */
.roster-cell.is-locked input {
	background: var(--br-page); color: var(--br-muted);
	border-style: dashed; cursor: not-allowed;
}
.roster-cell.is-locked .roster-lock {
	display: inline-flex; background: var(--br-ink);
	border: 1px solid var(--br-ink); color: #fff;
}
.roster-cell.is-locked .roster-lock:hover,
.roster-cell.is-locked .roster-lock:focus {
	display: inline-flex; background: var(--br-accent-dark);
	border: 1px solid var(--br-accent-dark); color: #fff;
}

/* required: raised by validate() on submit, cleared as soon as the field is
   typed into, so the red never outlives the problem. */
.roster-err { display: none; margin: 3px 0 0; font-size: 11px; line-height: 1.3; color: var(--br-danger); }
.roster-cell.has-error .roster-err { display: block; }
.roster-table input.is-invalid { border-color: var(--br-danger); background: #fdf3f3; }
.roster-table input.is-invalid:focus {
	border-color: var(--br-danger); box-shadow: 0 0 0 3px rgba(214, 69, 69, .15);
}

/* ---- summary (receipt) ---------------------------------------------------
   Reads top-to-bottom as an equation the customer can check by eye:
   gross → minus the discount as REAL MONEY → branding subtotal → products →
   what the basket actually gets. The card itself is a .branding-box, so it is
   a visual peer of sections 1-3. */
.branding-summary .sum-row {
	display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
	padding: 5px 0; font-size: 13px;
}
.branding-summary .sum-label { color: var(--br-text); }
/* the "(6 бр. × 25.00 €)" aside — how the figure on the right was reached */
.branding-summary .sum-label i { font-style: normal; font-size: 12px; color: var(--br-muted); }
.branding-summary .sum-val { font-weight: 700; color: var(--br-ink); white-space: nowrap; }

/* Admin only: the re-negotiable percentage. Sits between the label and the
   amount, inherits the row's green so it reads as part of the discount line. */
.branding-summary .sum-edit { display: inline-flex; align-items: center; gap: 2px; margin-left: auto; }
.branding-summary .sum-edit input[type="number"] {
	width: 46px; padding: 2px 4px; margin: 0;
	border: 1px solid var(--br-line); border-radius: 6px;
	background: var(--br-card); text-align: center;
	font-family: inherit; font-size: 12px; font-weight: 700; color: var(--br-ok);
	-moz-appearance: textfield;
}
.branding-summary .sum-edit input[type="number"]::-webkit-outer-spin-button,
.branding-summary .sum-edit input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.branding-summary .sum-edit input[type="number"]:focus { outline: none; border-color: var(--br-ok); }
.branding-summary .sum-edit em { font-style: normal; font-size: 12px; font-weight: 700; color: var(--br-ok); }

.branding-summary .sum-discount .sum-label,
.branding-summary .sum-discount .sum-val { color: var(--br-ok); }

.branding-summary .sum-branding {
	margin-top: 4px; padding-top: 8px; border-top: 1px solid var(--br-line);
}
.branding-summary .sum-branding .sum-label { font-weight: 700; color: var(--br-ink); }

.branding-summary .sum-grand {
	margin-top: 6px; padding-top: 10px; border-top: 2px solid var(--br-ink);
}
.branding-summary .sum-grand .sum-label {
	display: flex; align-items: center; gap: 8px;
	font-size: 14px; font-weight: 700; color: var(--br-ink);
}
.branding-summary .sum-grand .sum-label svg { flex: 0 0 auto; width: 18px; height: 18px; color: var(--br-accent); }
.branding-summary .sum-grand .sum-val { font-size: 22px; color: var(--br-accent-dark); }

/* ---- actions -------------------------------------------------------------- */
.branding-submit, .branding-approve {
	display: flex; align-items: center; justify-content: center; gap: 9px;
	width: 100%; margin-top: 11px; padding: 13px;
	border: 0; border-radius: 10px;
	background: var(--br-accent); color: #fff;
	font-size: 15px; font-weight: 700; font-family: inherit;
	letter-spacing: .01em; cursor: pointer;
	box-shadow: 0 4px 14px rgba(0, 173, 238, .28);
	transition: background-color .15s ease, box-shadow .15s ease, transform .1s ease;
}
.branding-submit svg, .branding-approve svg { width: 19px; height: 19px; pointer-events: none; }
.branding-submit:hover, .branding-approve:hover { background: var(--br-accent-dark); }
.branding-submit:active, .branding-approve:active { transform: translateY(1px); }
.branding-submit:disabled, .branding-approve:disabled {
	background: #c7d2dc; box-shadow: none; cursor: not-allowed;
}

/* ---- saving overlay ------------------------------------------------------- */
.branding-saving {
	position: fixed; top: 0; left: 0; right: 0; bottom: 0;
	display: flex; align-items: center; justify-content: center;
	background: rgba(246, 248, 250, .85); z-index: 9999;
}
.branding-saving-box {
	background: var(--br-ink); color: #fff; padding: 22px 30px; border-radius: 12px;
	font-weight: 700; text-align: center; box-shadow: 0 10px 40px rgba(16, 35, 54, .3);
}
.branding-saving-spin {
	display: block; width: 30px; height: 30px; margin: 0 auto 12px;
	border: 3px solid rgba(255, 255, 255, .25); border-top-color: #fff;
	border-radius: 50%; animation: brspin .8s linear infinite;
}
@keyframes brspin { to { transform: rotate(360deg); } }

/* ---- responsive ----------------------------------------------------------- */
@media (max-width: 900px) {
	/* below this the columns stack, so there is nothing to stick beside */
	.branding-col-preview { position: static; max-width: none; }
}
@media (max-width: 600px) {
	.branding-editor { padding: 10px 12px 24px; }
	.branding-editor h1 { font-size: 18px; }
	.branding-box { padding: 12px; }
	.size-rows { grid-template-columns: 1fr; }
	/* the receipt is a stacked list already; only the aside needs to wrap */
	.branding-summary .sum-row { flex-wrap: wrap; }
	.branding-summary .sum-grand .sum-val { font-size: 20px; }
	.stamp-item .stamp-head { flex-wrap: wrap; }
	.stamp-item .stamp-heading { flex-basis: calc(100% - 38px); }
	.stamp-item .stamp-color { order: 3; }
	.stamp-item .stamp-price { margin-left: auto; }
	.stamp-fields select.s-variant { max-width: 100%; }
}

/* ---- storefront overrides -------------------------------------------------
   style.css:1475 resets EVERY button on the site:

       button, button:focus { outline: none; border: 0px; display: inline-block }

   The bare `button` half (0,0,1) loses to our classes, but `button:focus`
   (0,1,1) outranks a plain class — so the moment a pill button is clicked its
   border collapses, and the flex action buttons turn into inline-blocks (which
   breaks the icon/label centering). These rules restore both, scoped to the
   editor, and give keyboard users back the focus ring the reset removes. */
.branding-editor .side-pick-btn,
.branding-editor .stamp-palette button,
.branding-editor .stamp-remove { box-sizing: border-box; }
.branding-editor .side-pick-btn:focus,
.branding-editor .stamp-palette button:focus,
.branding-editor .stamp-remove:focus { border: 1px solid var(--br-line-2); }
/* the reset also forces display:inline-block, which would un-centre the glyph */
.branding-editor .stamp-remove:focus { display: flex; }
.branding-editor .stamp-remove:focus:hover { border-color: var(--br-danger); }
.branding-editor .side-pick-btn:focus:hover,
.branding-editor .stamp-palette button:focus:hover,
.branding-editor .side-pick-btn.active:focus { border-color: var(--br-accent); }
.branding-editor .branding-submit:focus,
.branding-editor .branding-approve:focus { display: flex; }
/* the palette pills stack a title over a price, so the reset's inline-block
   would drop the price onto the same line the moment one is clicked */
.branding-editor .stamp-palette button:focus { display: flex; }
.branding-editor button:focus-visible { outline: 2px solid var(--br-accent); outline-offset: 2px; }

/* "Приложи и за друг продукт": note shown when the editor is pre-filled from
   another project's design. Uses the editor's own accent-soft tokens. */
.bp-seed-note {
	margin: 0 0 16px; padding: 10px 14px;
	background: var(--br-accent-soft); border: 1px solid #bfe9fb; border-radius: var(--br-r-sm);
	color: var(--br-accent-dark); font-size: 14px;
}
.bp-seed-note .fa { margin-right: 6px; }
