/**
 * MicroBite POS — Native EPO styles
 *
 * Hybrid layout: the previous EPO's familiar structure (group heading bars
 * with a light background, generously spaced full-width rows, label left …
 * price right, visible control on the far right) with the native build's
 * polish (rounded rows, dark selected state, hidden $0.00 prices).
 *
 * The real radio/checkbox inputs are visually hidden but stay in the DOM and
 * a11y tree — the row <label> is the tap target and .mbpos-epo__control is a
 * purely visual indicator, so native semantics, keyboard support and
 * template-clone state (checked attributes) all keep working.
 *
 * Uses Core Framework vars with px fallbacks, matching the rest of the modal.
 *
 * @since 1.4.0 (Session 3, revised per Carrum feedback)
 */

.mbpos-epo {
	display: flex;
	flex-direction: column;
	gap: var(--mbpos-space-xs, 12px);   /* st85: collapsed groups read as one related stack */
	margin: var(--mbpos-space-2xs, 8px) 0 var(--mbpos-space-s, 16px);
}

/* ── Group ───────────────────────────────────────────────────────────── */

.mbpos-epo__group {
	border: 0;
	margin: 0;
	padding: 0;
	min-width: 0;
}

/* Heading bar — a tappable warm chip. st85: consumes the --mbpos-epo-head-*
   tokens (driven by the Appearance "Product modal & EPO" card), sized to a
   44px tap target via PADDING rather than min-height so `align-items:
   baseline` keeps the title and summary on a true shared text baseline
   (min-height + baseline top-pins the text). */
.mbpos-epo__group-name {
	display: flex;
	align-items: baseline;
	gap: 8px;
	/* [fix4] st92's inset MOVED to the scoped rule that actually wins (search
	   `[data-mbpos] .mbpos-epo__group-name`). Declared here it was dead from
	   the day it shipped, so the overhang st92 set out to fix has been live
	   ever since. Nothing is inset from here. */
	font-size: var(--mbpos-epo-head-size, var(--mbpos-font-size-base, 14px));
	font-weight: var(--mbpos-epo-head-weight, 600);
	line-height: 20px;
	color: var(--mbpos-epo-head-color, var(--mbpos-color-heading, #1C1917));
	padding: 12px var(--mbpos-space-s, 14px);   /* 12+20+12 = 44px tap target */
	background: var(--mbpos-epo-head-bg, #EFEDE8);
	border-radius: var(--mbpos-radius-s, 6px);
	box-sizing: border-box;
	transition: background-color .15s ease, box-shadow .15s ease;
}

.mbpos-epo__req {
	color: var(--mbpos-color-danger, #B91C1C);
	font-weight: 700;
	margin-left: -4px;   /* st85: was order:2 (sorted after the chevron) — glue to the title: "Size*" */
}

/* ── Choices — spaced full-width rows ───────────────────────────────── */

.mbpos-epo__choices {
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding: 0 var(--mbpos-space-3xs, 4px) var(--mbpos-space-2xs, 8px);
}

.mbpos-epo__choice {
	position: relative;
	display: block;
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
}

/* Visually hidden but focusable input — keeps native semantics. */
.mbpos-epo__input {
	position: absolute;
	opacity: 0;
	width: 1px;
	height: 1px;
	margin: 0;
	pointer-events: none;
}

/* Row: label (flex) …… price …… control.
   [epo-fix2] Visible border on every row — the old transparent border made
   the list look like bare text and the selected tint was 5% opacity, which
   was invisible on most screens. Borders now use the skin's --mbpos-color-border
   token; the selected state switches to the full-contrast approach used on
   the storefront (dark bg, white text via --mbpos-color-selected-*). */
.mbpos-epo__row {
	display: flex;
	align-items: center;
	gap: var(--mbpos-space-xs, 12px);
	width: 100%;
	min-height: 44px;                            /* st85: mobile tap target */
	padding: var(--mbpos-space-2xs, 8px) var(--mbpos-space-s, 14px);
	border: 1px solid var(--mbpos-color-border, #E3E0DA);
	border-radius: var(--mbpos-radius-btn, 8px);   /* st87: rows are button-role — radius-btn (Bricks 8); radius-s stays the 6px heading value */
	background: var(--mbpos-color-surface, #ffffff);
	color: inherit;
	box-sizing: border-box;
	transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease, color .15s ease;
	user-select: none;
}

/* ── [hov1] The row answers the pointer ──────────────────────────────────
   Three row SHAPES exist and only one of them used to respond: the plain
   `.mbpos-epo__row`. A multi-level topping renders as `--seg`, a card with no
   `__row` inside it, so on a pizza the only thing that moved under the cursor
   was whichever pill you were directly over — the line itself was inert. The
   seg cases are declared beside this one rather than beside the card rules 800
   lines down, because "what a row does on hover" is one decision.

   `@media (hover: hover) and (pointer: fine)`: on a POS touchscreen a tapped
   element keeps :hover until something else is tapped, so an unguarded tint
   would sit on the last-touched row looking like a second, competing selected
   state. The query is not a phone/desktop test — it asks whether the pointer
   can hover at all, which is the actual question.

   `:not(.is-selected)` — Peter's call: a selected row does not take a hover.
   The plain row got that from source order (the selected rule below ties at
   (0,3,0) and wins on position); stating it makes the behaviour survive
   somebody moving either block, which is the failure fix4 spent an arc on. */
@media (hover: hover) and (pointer: fine) {

	.mbpos-epo__choice:not(.is-selected):hover .mbpos-epo__row {
		border-color: var(--mbpos-color-border-strong, #C9C4BA);
		background: var(--mbpos-color-surface-hover, #FAF9F7);
		color: inherit;
	}

	/* The seg card IS the row here — no `__row` exists inside it. ONE rule
	   covers both places a card can sit, and `.mbpos-epo__choices` is in the
	   selector to BUY BACK A TIER: dropping `:not(.is-selected)` below cost
	   one class, which would have tied this at (0,4,0) with box1's
	   `background: transparent` section override and handed the decision to
	   source order — where box1, 1600 lines lower, would have won and killed
	   the tint inside every section. The wrapper is present in both contexts
	   (sectioned and not), so (0,5,0) holds everywhere.
	   css-hover-test-hov1.js §2 computes the three numbers and asserts the
	   ranking, so a lost tier reddens instead of shipping.

	   [hov1-a] NO `:not(.is-selected)`, unlike the plain row above — and this
	   is the correction Peter's eyeball produced. On a pizza EVERY topping in
	   the Included section is `is-selected` at render (that is what Included
	   MEANS), so the guard switched hover off for a whole section: the Extras
	   answered the pointer and the Included ones sat dead. The two row shapes
	   need different answers to the same question because their selected
	   states are different things — a plain row's is a near-black FILL that a
	   tint would fight, a card's is a border colour a tint does not touch.

	   No border-color here either: on a card the border IS the selected
	   signal (P5), so strengthening it on hover would make an unselected
	   topping read as selected. */
	[data-mbpos] .mbpos-epo__choices .mbpos-epo__choice.mbpos-epo__choice--seg:hover {
		background: var(--mbpos-color-surface-hover, #FAF9F7);
		color: inherit;
	}
}

/* Keyboard focus ring via the hidden input. */
.mbpos-epo__input:focus-visible + .mbpos-epo__row {
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 35%, transparent);
}

.mbpos-epo__label {
	flex: 1;
	font-size: var(--mbpos-epo-option-size, var(--mbpos-font-size-base, 14px));
	line-height: 1.35;
	min-width: 0;
}

.mbpos-epo__desc {
	display: block;
	font-size: 11.5px;
	color: var(--mbpos-color-text-muted, #8a8f98);
	margin-top: 2px;
}

.mbpos-epo__price {
	font-size: var(--mbpos-font-size-s, 13px);
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: var(--mbpos-color-text-muted, #78716C);
	white-space: nowrap;
}

/* [sale1a] Struck-through was-price beside the charged add. Same grammar as
   the storefront sheet; the POS modal is inside [data-mbpos] already.
   [fix1] colour inherits — see the storefront sheet for why a fixed grey here
   is wrong on a selected row. */
.mbpos-epo__was {
	margin-right: 4px;
	font-weight: 400;
	opacity: 0.75;
	text-decoration: line-through;
	color: inherit;
}

/* ── Control indicator (visual radio / checkbox) ────────────────────── */

.mbpos-epo__control {
	flex: 0 0 auto;
	width: 20px;
	height: 20px;
	border: 2px solid var(--mbpos-color-border-strong, #c3c8cd);
	background: var(--mbpos-color-surface, #fff);
	border-radius: 50%;                       /* radio default */
	position: relative;
	transition: border-color .12s, background .12s;
}

.mbpos-epo__group[data-type="checkbox"] .mbpos-epo__control {
	border-radius: 5px;                       /* checkbox square */
}

/* [epo-fix2] Selected row — full-contrast, matching the storefront surface.
   The old 5% tint was invisible; this uses the skin's --mbpos-color-selected-bg
   for background and --mbpos-color-selected-text for text, so the selected row
   is immediately obvious and text is always readable. Price and desc inherit
   the white text colour via `color: inherit` and a small opacity step. */
.mbpos-epo__choice.is-selected .mbpos-epo__row,
.mbpos-epo__input:checked + .mbpos-epo__row {
	background: var(--mbpos-color-selected-bg, #1C1917);
	border-color: var(--mbpos-color-selected-bg, #1C1917);
	color: var(--mbpos-color-selected-text, #FFFFFF);
}

.mbpos-epo__choice.is-selected .mbpos-epo__row .mbpos-epo__price,
.mbpos-epo__input:checked + .mbpos-epo__row .mbpos-epo__price,
.mbpos-epo__choice.is-selected .mbpos-epo__row .mbpos-epo__desc,
.mbpos-epo__input:checked + .mbpos-epo__row .mbpos-epo__desc {
	color: inherit;
	opacity: .85;
}

.mbpos-epo__choice.is-selected .mbpos-epo__row .mbpos-epo__control,
.mbpos-epo__input:checked + .mbpos-epo__row .mbpos-epo__control {
	border-color: var(--mbpos-color-selected, #1C1917);
	background: linear-gradient(180deg,
		color-mix(in srgb, var(--mbpos-color-selected, #1C1917) 86%, #fff) 0%,
		var(--mbpos-color-selected, #1C1917) 100%);
}

/* Radio dot + checkbox tick pop in with a tiny spring — the micro-motion
   that separates "app" from "web form". ::after exists on every control so
   the transition has a start state; unselected it's scaled to zero. */
.mbpos-epo__group[data-type="radio"] .mbpos-epo__control::after {
	content: '';
	position: absolute;
	inset: 5px;
	border-radius: 50%;
	background: var(--mbpos-color-surface, #fff);
	transform: scale(0);
	transition: transform .18s cubic-bezier(.34,1.56,.64,1);
}
.mbpos-epo__group[data-type="radio"] .mbpos-epo__choice.is-selected .mbpos-epo__control::after,
.mbpos-epo__group[data-type="radio"] .mbpos-epo__input:checked + .mbpos-epo__row .mbpos-epo__control::after {
	transform: scale(1);
}

/* Checkbox tick */
.mbpos-epo__group[data-type="checkbox"] .mbpos-epo__control::after {
	content: '';
	position: absolute;
	left: 5px;
	top: 1px;
	width: 5px;
	height: 10px;
	border: solid var(--mbpos-color-surface, #fff);
	border-width: 0 2px 2px 0;
	transform: rotate(45deg) scale(0);
	transform-origin: 60% 60%;
	transition: transform .18s cubic-bezier(.34,1.56,.64,1);
}
.mbpos-epo__group[data-type="checkbox"] .mbpos-epo__choice.is-selected .mbpos-epo__control::after,
.mbpos-epo__group[data-type="checkbox"] .mbpos-epo__input:checked + .mbpos-epo__row .mbpos-epo__control::after {
	transform: rotate(45deg) scale(1);
}

/* ── Validation ──────────────────────────────────────────────────────── */

.mbpos-epo__error {
	display: none;
	font-size: 12.5px;
	color: var(--mbpos-color-danger, #B91C1C);
	margin-top: 6px;
	padding-left: var(--mbpos-space-3xs, 4px);
}

.mbpos-epo__group--error .mbpos-epo__error {
	display: block;
}

.mbpos-epo__group--error .mbpos-epo__group-name {
	background: var(--mbpos-color-danger-subtle, rgba(185,28,28,0.08));
	box-shadow: inset 3px 0 0 var(--mbpos-color-danger, #B91C1C);
}



/* ── Note field ──────────────────────────────────────────────────────── */

.mbpos-epo__note {
	display: flex;
	flex-direction: column;
	gap: var(--mbpos-space-2xs, 8px);
	padding: 0 var(--mbpos-space-3xs, 4px);
	margin-top: var(--mbpos-space-2xs, 6px);
}

.mbpos-epo__note-label {
	/* st90: plain left-aligned heading flush with the textarea edge —
	   the old chip treatment (own bg + padding) indented the text and
	   misaligned it from the field below. */
	display: block;
	text-align: left;
	font-size: var(--mbpos-font-size-s, 13px);
	font-weight: 600;
	color: var(--mbpos-color-heading, #1C1917);
	padding: 0;
	background: transparent;
	border-radius: 0;
	margin: 0 0 4px;
}

.mbpos-epo__note-input {
	width: 100%;
	border: 1.5px solid var(--mbpos-color-border, #e3e5e8);
	border-radius: var(--mbpos-radius-s, 8px);
	padding: var(--mbpos-space-xs, 12px) var(--mbpos-space-xs, 14px);
	font: inherit;
	font-size: var(--mbpos-font-size-s, 14px);
	resize: vertical;
	min-height: 44px;
	background: var(--mbpos-color-surface, #fff);
	box-sizing: border-box;
}

.mbpos-epo__note-input:focus {
	outline: none;
	border-color: var(--mbpos-color-heading, #1d2327);
}

/* ── Cart addons block (structured per-group display) ───────────────── */
/* Mirrors the previous EPO cart layout: group title, "+ choice" rows with
   right-aligned prices, addons total, note. Indented with a soft left rule
   so it reads as belonging to the item above. */

.mbpos-cart-addons {
	display: flex;
	flex-direction: column;
	gap: 6px;
	margin-top: 4px;
	padding-left: 10px;
	/* [ce7b] The right padding was never here. Addon rows put their price on
	   the right, so those figures have always sat flush against the block's
	   edge — a tint has no edge so nothing showed it, and ce7's ring did.
	   Exposed, not caused, and worth fixing whatever the hover state ends up
	   being. Matches the left so the block is symmetric. */
	padding-right: 10px;
	/* [ce3.4] Width via --mbpos-edit-rule so the hover overlay can inset itself
	   past this rule by exactly its thickness and leave it crisp. Undefined
	   outside an editable block ⇒ the 2px fallback. One number, two readers. */
	border-left: var(--mbpos-edit-rule, 2px) solid var(--mbpos-color-border, #ebebed);
	font-size: 12px;
	line-height: 1.45;
}

.mbpos-cart-addons__group-title {
	font-weight: 600;
	color: var(--mbpos-color-text-muted, #50575e);
	margin-bottom: 1px;
}

.mbpos-cart-addons__item {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 10px;
	color: var(--mbpos-color-text-muted, #6b7280);
}

.mbpos-cart-addons__item-price {
	white-space: nowrap;
	color: var(--mbpos-color-text-muted, #50575e);
}

.mbpos-cart-addons__total {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 10px;
	margin-top: 2px;
	padding-top: 5px;
	border-top: 1px dashed var(--mbpos-color-border, #e3e5e8);
	font-weight: 600;
	color: var(--mbpos-color-text-muted, #50575e);
}

.mbpos-cart-addons__note {
	color: var(--mbpos-color-warning, #9a6700);
}

/* ════════════════════════════════════════════════════════════════════
   Combo / meal deal modal (Session C3)
   Slot list (chevron rows, Amalfi pattern) + drill-in image picker.
   ════════════════════════════════════════════════════════════════════ */

.mbpos-combo {
	display: flex;
	flex-direction: column;
	gap: var(--mbpos-space-s, 12px);
}

/* Slot-list gutter (SE6): the takeover sheets carry a 1.2rem side gutter,
   so the slot rows (and the combo note below them) must match — staff
   flagged the slot rows running wider than everything else. The sheets
   are absolutely positioned, so this padding can't double up on them.
   If a template adds its own gutter to the addons container, zero this
   out in the builder: .mbpos-combo { --mbpos-combo-gutter: 0px; } */
.mbpos-combo > .mbpos-combo__slots,
.mbpos-combo > .mbpos-epo__note {
	padding-left: var(--mbpos-combo-gutter, var(--mbpos-space-2xs, 12px));
	padding-right: var(--mbpos-combo-gutter, var(--mbpos-space-2xs, 12px));
	margin: var(--mbpos-space-2xs, 6px) 0 var(--mbpos-space-s, 12px);
}

/* st93 (Peter): the SAME gutter for a standalone (non-combo) EPO form in the
   plugin's product modal — a Margherita's Size rows ran edge-to-edge while a
   half-n-half's sat inset 12px (the combo sheet's padding). Scoped to the
   plugin lightbox + direct child of the addons mount so it can't touch
   Bricks-built modals or the per-slot forms inside combo sheets (those
   already inherit the sheet's padding). Override per-template with
   --mbpos-epo-gutter if a builder adds its own. */
.mbpos-lightbox__panel .mbpos-products-detail__addons > .mbpos-epo {
	padding-left: var(--mbpos-epo-gutter, var(--mbpos-space-2xs, 12px));
	padding-right: var(--mbpos-epo-gutter, var(--mbpos-space-2xs, 12px));
}

/* ── Slot list ──────────────────────────────────────────────────────── */

.mbpos-combo__slots {
	display: flex;
	flex-direction: column;
	gap: var(--mbpos-space-xs, 10px);
}

.mbpos-combo__slot {
	display: flex;
	align-items: center;
	gap: var(--mbpos-space-xs, 10px);
	width: 100%;
	padding: var(--mbpos-space-xs, 12px) var(--mbpos-space-xs, 14px);
	border: 1.5px solid var(--mbpos-combo-slot-border, var(--mbpos-color-border, #e3e5e8));
	border-radius: var(--mbpos-radius-s, 8px);
	background: var(--mbpos-color-surface, #fff);
	font: inherit;
	text-align: left;
	cursor: pointer;
	transition: border-color .15s, background .15s, box-shadow .15s;
	box-sizing: border-box;
	-webkit-tap-highlight-color: transparent;
}

/* [auto1c] cursor only — the border and background now come from the
   --filled rule below. The old `background: --mbpos-color-bg` was the token
   a PICKED slot uses for its HOVER state, so an included item permanently
   looked like the row under the cursor. */
.mbpos-combo__slot--auto { cursor: default; }

/* [auto1] Included-item thumbnail — the POS twin of the storefront rule.
   Slightly larger for touch-distance legibility on a terminal. */
.mbpos-combo__slot--auto .mbpos-combo__slot-thumb {
	flex: 0 0 auto;
	width: 44px;
	height: 44px;
	object-fit: cover;
	border-radius: 6px;
	/* No margin: .mbpos-combo__slot is already `display:flex` with a gap,
	   so a margin here would double the spacing against every other row. */
}
.mbpos-combo__slot--auto .mbpos-combo__slot-thumb--ph {
	display: block;
	background: var(--mbpos-color-border, #e5e7eb);
}

.mbpos-combo__slot--pick {
	background: var(--mbpos-combo-slot-bg, #f8f9fb);
}
.mbpos-combo__slot--pick:hover {
	border-color: var(--mbpos-color-border-strong, #aab0b8);
	background: var(--mbpos-combo-slot-hover, #eef1f6);
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}

/* [auto1c] --auto rides the same declarations as --filled, for the same
   reason the status circle does: an included item IS answered, so it should
   read as answered — same border, same surface, no hover state. Joining the
   rule (rather than copying the values) is what stops the two drifting when
   the tokens change. */
.mbpos-combo__slot--filled,
.mbpos-combo__slot--auto {
	border-color: var(--mbpos-combo-tick-bg, var(--mbpos-color-success, #22c55e));
	background: var(--mbpos-color-surface, #fff);
}
.mbpos-combo__slot--filled:hover {
	background: var(--mbpos-color-bg, #f8f9fa);
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}

.mbpos-combo__slot--error { border-color: var(--mbpos-color-danger, #d63638); }

.mbpos-combo__slot-label {
	font-weight: 600;
	font-size: var(--mbpos-font-size-s, 14px);
	white-space: nowrap;
}

.mbpos-combo__req { color: var(--mbpos-color-danger, #d63638); margin-left: 3px; }

.mbpos-combo__slot-picked {
	font-size: var(--mbpos-font-size-s, 13.5px);
	color: var(--mbpos-color-text-muted, #50575e);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* [sum1a/D3] The row's price cell. Sits between the text and the Customise
 * affordance, right-aligned and tabular so a column of rows reads as a
 * column of figures. Empty when nothing was added — stampPick writes '' —
 * so it collapses to nothing rather than printing +$0.00, matching the
 * sparse grammar surcharges and locked preset lines already use. */
.mbpos-combo__slot-add {
	margin-left: auto;
	padding-left: 8px;
	font-size: var(--mbpos-font-size-s, 13.5px);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
	color: var(--mbpos-color-text, #1d2327);
}

.mbpos-combo__slot-included { flex: 1; font-size: var(--mbpos-font-size-s, 13.5px); color: var(--mbpos-color-text-muted, #50575e); }

.mbpos-combo__slot-chevron {
	color: var(--mbpos-color-border-strong, #a7aaad);
	font-size: 1.6em;
	line-height: 1;
	transition: transform .15s;
}
.mbpos-combo__slot--pick:hover .mbpos-combo__slot-chevron {
	transform: translateX(2px);
}

.mbpos-combo__slot-tick { color: var(--mbpos-color-success, #1a7f37); font-weight: 700; }

/* Per-slot image (Phase C, st81) — thumbnail in the slot row. */
.mbpos-combo__slot-img {
	width: 48px;
	height: 48px;
	border-radius: var(--mbpos-radius-xs, 5px);
	border: 1px solid var(--mbpos-color-border, #e8eaed);
	object-fit: cover;
	flex-shrink: 0;
}

/* Slot info wrapper — vertical stack of label + picked/hint (st81). */
.mbpos-combo__slot-info {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 2px;
}

/* Hint text shown until a pick is made (st81). */
.mbpos-combo__slot-hint {
	font-size: var(--mbpos-font-size-xs, 12px);
	color: var(--mbpos-color-text-muted, #888);
}
.mbpos-combo__slot--filled .mbpos-combo__slot-hint { display: none; }

.mbpos-combo__error {
	display: block;
	font-size: 12.5px;
	color: var(--mbpos-color-danger, #d63638);
	min-height: 1em;
}

/* ── Picker (drill-in view) ─────────────────────────────────────────── */

.mbpos-combo__picker-head {
	display: flex;
	align-items: center;
	gap: var(--mbpos-space-xs, 10px);
	margin-bottom: var(--mbpos-space-2xs, 8px);
}

.mbpos-combo__back {
	display: inline-flex;
	align-items: center;
	border: 1.5px solid var(--mbpos-color-border, #e3e5e8);
	background: var(--mbpos-color-surface, #fff);
	border-radius: var(--mbpos-radius-s, 6px);
	padding: 6px 12px;
	font: inherit;
	font-size: var(--mbpos-font-size-s, 13px);
	cursor: pointer;
	line-height: 1.4;
	-webkit-tap-highlight-color: transparent;
	transition: background .12s;
}
.mbpos-combo__back:hover { background: var(--mbpos-color-bg, #f7f7f8); }

.mbpos-combo__picker-title { font-weight: 600; font-size: var(--mbpos-font-size-base, 15px); }

.mbpos-combo__grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
	gap: var(--mbpos-space-2xs, 8px);
}

.mbpos-combo__option {
	display: flex;
	flex-direction: column;
	gap: 6px;
	padding: var(--mbpos-space-2xs, 8px);
	border: 1.5px solid var(--mbpos-color-border, #e3e5e8);
	border-radius: var(--mbpos-radius-s, 8px);
	background: var(--mbpos-color-surface, #fff);
	font: inherit;
	text-align: left;
	cursor: pointer;
	transition: border-color .12s, background .12s, box-shadow .12s;
	box-sizing: border-box;
	-webkit-tap-highlight-color: transparent;
}

.mbpos-combo__option:hover {
	border-color: var(--mbpos-color-border-strong, #aab0b8);
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}

.mbpos-combo__option.is-selected {
	border-color: var(--mbpos-color-heading, #1d2327);
	background: var(--mbpos-color-bg, #f7f8f9);
}

.mbpos-combo__option-img {
	width: 100%;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	border-radius: calc(var(--mbpos-radius-s, 8px) - 2px);
	background: var(--mbpos-color-bg, #f1f2f3);
	display: block;
}

.mbpos-combo__option-img--ph { /* placeholder block when no image */ }

.mbpos-combo__option-name { font-size: var(--mbpos-font-size-s, 13px); font-weight: 600; line-height: 1.3; }

.mbpos-combo__option-sur { font-size: 12px; font-weight: 600; color: var(--mbpos-color-text-muted, #50575e); }

/* Currently-closed component (day/time availability) — greyed at picker-open
   time by pos-combo-render.js; taps are ignored, server rejects regardless. */
.mbpos-combo__option.is-unavailable {
	opacity: 0.45;
	cursor: not-allowed;
	filter: grayscale(1);
}
.mbpos-combo__option.is-unavailable:hover { border-color: var(--mbpos-color-border, #e3e5e8); }

.mbpos-combo__option-when {
	font-size: 11px;
	font-weight: 600;
	color: var(--mbpos-color-text-muted, #50575e);
	text-transform: uppercase;
	letter-spacing: 0.03em;
}

/* ── Card availability badge ────────────────────────────────────────── */

.mbpos-card-avail {
	position: absolute;
	top: 8px;
	left: 8px;
	z-index: 3;
	background: rgba(29, 35, 39, 0.85);
	color: #fff;
	font-size: 11px;
	font-weight: 600;
	line-height: 1;
	padding: 5px 8px;
	border-radius: 999px;
	pointer-events: none;
	max-width: calc(100% - 16px);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

/* ── Per-slot EPO inside combos (Session SE1) ───────────────────────── */

/* Options step panel: same head styles as the picker (shared classes),
   the embedded .mbpos-epo form renders with its normal styles. */
.mbpos-combo__opts .mbpos-epo {
	margin-top: 4px;
}

/* ── Drill takeover sheet (SE5) ───────────────────────────────────── */

/* ── [par1-a] THE SHEET'S CONTAINING BLOCK ───────────────────────────────
   The rule below has said since SE1 that the sheet covers "the whole modal
   panel (.mbpos-lightbox__panel is position:relative — the containing block)".
   THAT WAS NEVER TRUE. `.mbpos-products-detail__wrapper` sits between them and
   is `position: relative` too (mbpos-pos-layout.css), so it — not the panel —
   has always been the containing block, and `inset: 0` has always meant "the
   height of the modal's own content" rather than "the height of the panel".

   Measured on Peter's screen: panel 38→730, wrapper 38→573. The sheet stopped
   **157px above the panel bottom**, leaving a 65px band of live modal content
   between the Done bar and the Add bar. That is the gap he reported, it is
   what he saw scrolling underneath, and it predates par1 entirely — par1's
   12px was a second, smaller leak stacked on top of this one. The same false
   assumption is why the drill-dim block a few hundred lines up says the
   underlying content is "covered, not dimmed": it never was.

   `:has()` rather than the `.mbpos-drill` class, deliberately. The condition
   IS "a sheet is open" — asking the DOM directly means the containing block
   cannot drift out of step with a JS class toggle, which is a real failure
   mode here (see the guard comment at pos-combo-render.js ~711, where a
   missed toggle regressed SE4). Same :has() support floor the Add-greying
   rule already assumes. If it ever fails to parse, the sheet falls back to
   today's behaviour — short, not broken.

   (0,3,0) — above the base rule's (0,1,0) on rank, not on order. */
.mbpos-products-detail__wrapper:has(.mbpos-combo__picker:not([hidden])),
.mbpos-products-detail__wrapper:has(.mbpos-combo__opts:not([hidden])) {
	position: static;
}

/* The picker and options steps open as their OWN screen: an opaque sheet
   covering the whole modal panel — see the block directly above for what
   makes `.mbpos-lightbox__panel` actually be the containing block, which is
   a thing this rule assumed for five arcs without it being so. Staff
   feedback drove this: the cover image pushed the options 3/4 down the
   screen, the combo note / qty / Add stayed visible (and undimmed)
   below the step, and sticky-Done floated mid-content because the step
   was never its own scroll container. As a sheet: starts at the top,
   covers everything (no dimming needed), scrolls independently, and
   sticky head/foot are well-defined. z-index 20 sits above the lightbox
   close (z 10) deliberately — Back is the one exit from a step; an
   accidental × would dump the half-built combo. ESC still closes. */
.mbpos-lightbox__panel .mbpos-combo__picker:not([hidden]),
.mbpos-lightbox__panel .mbpos-combo__opts:not([hidden]) {
	position: absolute;
	inset: 0;
	z-index: 20;
	background: var(--mbpos-color-surface, #fff);
	overflow-y: auto;
	-webkit-overflow-scrolling: touch;
	/* [par1] NO BOTTOM PADDING, and that is load-bearing rather than tidying.
	   A sticky box is confined to its CONTAINING BLOCK — here the sheet's
	   content box — while a scroll container clips at its PADDING box. With a
	   12px bottom padding the two disagree by exactly 12px: the pinned foot
	   could not reach the bottom edge, and the strip below it stayed inside
	   the scrollport, so content scrolled through it in plain sight. The foot
	   bar owns the gutter now (as its own padding), which is the same shape
	   the product modal's footer has always had. */
	padding: 0 var(--mbpos-space-2xs, 12px) 0;
	border-radius: inherit;
	display: flex;
	flex-direction: column;
}

/* Back/title bar pinned to the top of the sheet. */
.mbpos-lightbox__panel .mbpos-combo__picker:not([hidden]) .mbpos-combo__picker-head,
.mbpos-lightbox__panel .mbpos-combo__opts:not([hidden]) .mbpos-combo__picker-head {
	position: sticky;
	top: 0;
	z-index: 2;
	background: var(--mbpos-color-surface, #fff);
	margin: 0 calc(-1 * var(--mbpos-space-2xs, 12px));
	padding: var(--mbpos-space-2xs, 12px);
	border-bottom: 1px solid var(--mbpos-color-bg, #f1f2f3);
}

/* ── [par1] The foot bar ─────────────────────────────────────────────────
   Done used to be the sticky element itself, and it could never reach the
   bottom of the sheet. A sticky box is confined to its CONTAINING BLOCK (the
   sheet's content box); a scroll container clips at its PADDING box. The
   sheet's 12px bottom padding sat between the two, so the button stopped 12px
   short and that strip — still inside the scrollport — showed the toppings
   sliding underneath. Peter reported both halves as one symptom, and they are
   one bug.

   The bar is the exact mirror of `.mbpos-combo__picker-head` above it: same
   full-bleed negative margin, same opaque surface, pinned to the opposite
   edge. It also takes the PRODUCT FOOTER's geometry, because the sheet covers
   the footer — you never see the two at once, you see one replace the other,
   and a Done that sits somewhere other than where Add sits reads as a jump on
   close. `margin-top: auto` moved here from the button; it is what holds the
   bar at the foot when the options are shorter than the sheet.

   The invariant, for whoever amends this: NOTHING SCROLLS BELOW THE PINNED
   FOOT. Sticky + bottom:0 is one way to pay for it and not the property
   itself — combo-parity-test-par1.js §3 asserts the property (the scroller
   carries no bottom padding for content to show through) rather than the
   mechanism. See MBPOS-CE7-HANDOVER §2 for why that distinction keeps being
   the thing that matters. */
[data-mbpos] .mbpos-combo__opts-foot {
	position: sticky;
	bottom: 0;
	z-index: 2;
	margin: auto calc(-1 * var(--mbpos-space-2xs, 12px)) 0;
	padding: var(--mbpos-space-m, 24px) var(--mbpos-space-xs, 12px);
	background: var(--mbpos-color-surface, #fff);
	box-shadow: 0 -6px 16px -8px rgba(0, 0, 0, 0.35);
	box-sizing: border-box;
}

/* Done — commits the pick. Geometry matches `.mbpos-products-detail__add`
   (44px floor, button radius) so the two land in the same place. */
.mbpos-combo__opts-done {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	min-height: 44px;
	padding: var(--mbpos-space-xs, 12px) var(--mbpos-space-m, 24px);
	border: 0;
	border-radius: var(--mbpos-radius-btn, 8px);
	background: var(--mbpos-combo-done-bg, var(--mbpos-color-primary, #1d2327));
	color: var(--mbpos-combo-done-text, var(--mbpos-color-primary-text, #fff));
	font: inherit;
	font-size: var(--mbpos-font-size-base, 15px);
	font-weight: 700;
	cursor: pointer;
	/* [par1] The upward lift shadow moved to `.mbpos-combo__opts-foot`. On the
	   button it drew a line ACROSS the bar rather than at its edge, which is
	   where content actually passes. */
	text-align: center;
	letter-spacing: 0.02em;
	line-height: 1.4;
	box-sizing: border-box;
	-webkit-tap-highlight-color: transparent;
	transition: background .12s, opacity .12s;
}
.mbpos-combo__opts-done:hover {
	background: var(--mbpos-combo-done-bg, var(--mbpos-color-primary-hover, #2c3338));
	opacity: 0.9;
}
.mbpos-combo__opts-done:active {
	opacity: 0.85;
}

/* ── Slot status indicators ──────────────────────────────────────────
   Empty circle for pending, green tick for filled. Purely visual cue
   so staff can see at a glance what's done and what needs attention. */
.mbpos-combo__slot-status {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 22px;
	height: 22px;
	border-radius: 50%;
	border: 2px solid var(--mbpos-color-border, #d2d6da);
	flex-shrink: 0;
	font-size: 13px;
	transition: border-color 0.15s, background 0.15s;
}
.mbpos-combo__slot-status::after {
	content: '';
}
/* [auto1b] --auto rides the SAME declarations as --filled: an included item
   is answered by definition, so it should look answered. Joined here rather
   than given the --filled class, because mbpos-guidance.js counts .--filled
   rows for the progress sentence and an auto slot is not a step. */
.mbpos-combo__slot--filled .mbpos-combo__slot-status,
.mbpos-combo__slot--auto .mbpos-combo__slot-status {
	border-color: var(--mbpos-combo-tick-bg, var(--mbpos-color-success, #22c55e));
	background: var(--mbpos-combo-tick-bg, var(--mbpos-color-success, #22c55e));
	color: var(--mbpos-color-success-text, #fff);
}
.mbpos-combo__slot--filled .mbpos-combo__slot-status::after,
.mbpos-combo__slot--auto .mbpos-combo__slot-status::after {
	content: '\2713';
}
.mbpos-combo__slot--error .mbpos-combo__slot-status {
	border-color: var(--mbpos-color-danger, #dc2626);
}

/* ── Slot layout — theme isolation (st81) ────────────────────────────
   Slots are <div role="button"> to avoid theme button overrides.
   These scoped rules are belt-and-braces for themes that target
   [role="button"] or apply broad box-model resets. */
[data-mbpos] .mbpos-combo__slot {
	display: flex;
	align-items: center;
	text-align: left;
}
[data-mbpos] .mbpos-combo__slot-info {
	display: flex;
	flex-direction: column;
	text-align: left;
}
[data-mbpos] .mbpos-combo__slot-img {
	display: block;
}

/* ── Add button greyed until combo complete ──────────────────────────
   Pure CSS approach using :has() — when ANY pick slot in the combo is
   still empty, the Add button in the same modal is greyed out. Staff
   can still see the price building up as they make selections.
   :has() support: Chrome 105+, Firefox 121+, Safari 15.4+. */
.mbpos-lightbox__content--live:has(.mbpos-combo__slot--pick:not(.mbpos-combo__slot--filled)) .mbpos-products-detail__add {
	opacity: 0.4;
	pointer-events: none;
	filter: grayscale(0.5);
}
/* Breathing room so the last group can scroll clear of the pinned Done. */
.mbpos-combo__opts .mbpos-epo { padding-bottom: var(--mbpos-space-2xs, 12px); }

/* Drill dim (SE4) — kept ONLY as graceful degradation for a cached old
   stylesheet: with the takeover sheet the underlying content is covered,
   not dimmed. Footer + combo note included since staff flagged them. */
.mbpos-drill .mbpos-products-detail__cover,
.mbpos-drill [data-mbpos-field="modal-img"],
.mbpos-drill .mbpos-products-detail__info,
.mbpos-drill .mbpos-products-detail__footer,
.mbpos-drill .mbpos-combo > .mbpos-epo__note {
	opacity: 0.25;
	transition: opacity 0.2s ease;
}

/* "Customise ›" tag on picker options whose product has EPO groups. */
.mbpos-combo__option-cust {
	font-size: 11px;
	font-weight: 600;
	color: var(--mbpos-color-text-muted, #50575e);
}

/* Slot row picked text can now carry an options summary — the base rule
   already ellipsizes; min-width:0 lets the flex item actually shrink. */
.mbpos-combo__slot-picked {
	min-width: 0;
}

/* [hh1] "Customise" on a filled slot row — the way back into a pick's
   toppings now that tapping the pizza commits it outright. Same chip
   vocabulary as the EPO group's Customise, so the two read as one idea. */
.mbpos-combo__slot-cust {
	flex: 0 0 auto;
	font-size: 12px;
	font-weight: 600;
	line-height: 20px;
	padding: 3px 12px;
	border: 1px solid var(--mbpos-epo-cta-border, var(--mbpos-color-border-strong, rgba(0,0,0,0.25)));
	border-radius: 999px;
	background: var(--mbpos-epo-cta-bg, var(--mbpos-color-surface, #ffffff));
	color: var(--mbpos-epo-cta-text, var(--mbpos-color-heading, #1C1917));
	cursor: pointer;
	white-space: nowrap;
}
.mbpos-combo__slot-cust[hidden] { display: none; }
.mbpos-combo__slot-cust:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 35%, transparent);
}
/* The tile chevron is hidden on auto-commit choices (hh1) — belt and braces
   for skins that override [hidden]'s default display:none. */
.mbpos-combo__option-cust[hidden] { display: none; }

/* Indented per-slot option rows inside the cart addons block. */
.mbpos-cart-addons__item--sub {
	padding-left: 14px;
}
.mbpos-cart-addons__note--slot {
	padding-left: 14px;
	font-style: italic;
}

/* ── [hidden] must ALWAYS win (Session SE3) ─────────────────────────── */
/* Author display rules (.mbpos-combo__slots { display:flex } above)
   override the UA stylesheet's [hidden] { display:none } — on real sites
   the slot list never visually hid, stacking it above the open picker/
   options panel (the chicken2 staging report, latent since C3; invisible
   to jsdom tests that only read the hidden PROPERTY). One !important
   guard makes the attribute authoritative for every combo view, present
   and future. */
.mbpos-combo [hidden],
.mbpos-epo [hidden] {
	display: none !important;
}

/* ── [px1] The price cell ─────────────────────────────────────────────
   The POS twin of the storefront rule, and the contract is identical: the
   cell renders in every state, its width does not depend on the state, and
   the figure inside is what THIS ROW adds to the order. See
   class-mbpos-epo-product-inject.php for the reasoning in full.

   min-width is load-bearing — "Included" is the longest string it holds, so
   reserving less would let the label reflow when a free topping is doubled,
   which is the shift xtra3 just removed by a different route. */
.mbpos-epo__price {
	flex: 0 0 auto;
	min-width: 7ch;
	text-align: right;
	font-variant-numeric: tabular-nums;
}

/* ── [tri1] The segmented level control ───────────────────────────────
   The POS twin of the storefront's, shipped in the same arc on purpose: a
   window where the storefront shows segments and the POS shows a 2x checkbox
   is two surfaces answering one question differently, which is what pp2d-a's
   cross-surface parity exists to prevent.

   WHAT THE 2x PILL BLOCK HERE USED TO DO, and why none of it is needed:
     - it was `display:none` until its row was ticked (xtra3 removed that,
       because a control the customer cannot see is a feature they do not
       know exists). Segments are always present, so the reveal is gone by
       construction rather than by rule.
     - it carried the pressed state as `.is-on` + `aria-pressed`. A segment
       carries `.is-on` + `aria-checked`, because the control is now a
       radiogroup and "checked" is what a radio reports.

   THE INVARIANT SURVIVES UNCHANGED (xtra2 D2, and it matters more here
   because there are N of these per row instead of one): this box is IDENTICAL
   in every state. Padding, border-width, min-height and font do not vary
   between unpressed, hovered and pressed. Only colour moves. If you are
   adding geometry to a state rule below, you are reintroducing the shift
   xtra2 removed. epo-extra-test-xtra2.js §3 scans for exactly that and does
   not care which control it is scanning. */
/* [epo-fix3] Added border, background and padding to the seg choice so it
   reads as a contained card — same visual weight as the .mbpos-epo__row
   treatment in epo-fix2. Without these, the seg rows were bare text with
   floating pills. The selected border strengthens to --border-strong so the
   active topping is distinguishable. */
/* [fix4] COMPOUND-SCOPED, and that is the whole fix. Written bare at (0,1,0)
   this block lost every one of its layout declarations to the st82 theme-
   isolation rule `[data-mbpos] .mbpos-epo__choice { display: block }` at
   (0,2,0) — a seg card carries both classes, so the card has never laid out
   as a column since tri1 shipped. (0,3,0) wins on specificity rather than on
   source order, so moving either block cannot silently undo it. No
   `!important`: CSS-ISOLATION-STANDARD Rule 2 forbids it and specificity is
   sufficient here. Fenced by css-cascade-test-fix4.js §3B/§4. */
[data-mbpos] .mbpos-epo__choice.mbpos-epo__choice--seg {
	display: flex;
	flex-direction: column;
	align-items: stretch;
	gap: 6px;
	padding: var(--mbpos-space-2xs, 8px) var(--mbpos-space-s, 14px);
	background: var(--mbpos-color-surface, #ffffff);
	border: 1px solid var(--mbpos-color-border, #E3E0DA);
	border-radius: var(--mbpos-radius-btn, 8px);
	/* [hov1] background-color joins the list — the hover state for this card
	   is declared with the other row hovers near the top of this sheet, and a
	   transition that names only border-color would snap the tint. */
	transition: border-color .15s ease, background-color .15s ease;
}

.mbpos-epo__choice--seg.is-selected {
	border-color: var(--mbpos-color-border-strong, #C9C4BA);
}

.mbpos-epo__choice--seg .mbpos-epo__label {
	font-weight: 600;
	font-size: var(--mbpos-epo-option-size, var(--mbpos-font-size-base, 14px));
	line-height: 1.35;
	padding: 4px 0 2px;
}

/* [epo-fix1] The seg path has no .mbpos-epo__row wrapper, so the
   .mbpos-epo__control indicator never receives its selected-state styling
   — it shows as a permanently empty circle. The segments ARE the control;
   this indicator is redundant. Same fix as epo-sf-fix2 on the storefront. */
.mbpos-epo__choice--seg .mbpos-epo__control {
	display: none;
}

/* D13 — the segments wrap beneath the name. On the POS the row already
   reserves a 44px floor with a transparent 1.5px border, so this does not
   change row height on its own; what it changes is that a long topping name
   no longer competes with the control for horizontal space, because they are
   no longer on the same line. That is xtra3's accepted cost (checklist 87)
   removed rather than inherited. */
.mbpos-epo__segs {
	display: flex;
	flex-wrap: wrap;
	align-items: stretch;
	gap: 6px;
	min-width: 0;
}

.mbpos-epo__seg {
	display: inline-flex;
	/* [fix5] CENTRE, not baseline. `min-height` gives the pill a cross-size
	   floor; a single flex line is stretched to that floor, and baseline
	   alignment then pins the text to the TOP of it, so every pixel of slack
	   lands under the words — Peter's "padding on the bottom". The name and the
	   price carry the same font-size, so nothing is lost by centring: their
	   baselines still agree. */
	align-items: center;
	justify-content: center;
	gap: 5px;
	box-sizing: border-box;
	margin: 0;
	/* [seg2d] `position: relative` anchors the tick; the wider symmetric
	   padding is both the tick's gutter and the roomier pill Peter asked for
	   two rounds ago. */
	position: relative;
	padding: 4px 18px;
	min-height: 32px;
	color: var(--mbpos-color-text-muted, #8a8f98);
	background: var(--mbpos-color-surface, #fff);
	border: 1.5px solid var(--mbpos-color-border-strong, rgba(120,113,108,0.38));
	border-radius: 999px;
	font: inherit;
	font-size: 12px;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	line-height: 1.4;
	text-align: center;
	white-space: nowrap;
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
	transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}
.mbpos-epo__seg:hover {
	border-color: var(--mbpos-color-primary, #C2410C);
	color: var(--mbpos-color-primary, #C2410C);
}
.mbpos-epo__seg:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 35%, transparent);
}
.mbpos-epo__seg:active {
	transform: translateY(0.5px);
}
.mbpos-epo__seg:disabled {
	opacity: .55;
	cursor: default;
}
/* Row selected — the UNPRESSED segments un-mute. Colour only, same rule the
   2x control had, same reason: twenty always-visible controls at full
   contrast is real noise and muting answers it without costing geometry.

   [fix6] `:not(.is-on)` is LOAD-BEARING, and its absence was a live defect.
   Without it this rule matched the PRESSED segment too, at (0,3,0) against
   `.mbpos-epo__seg.is-on` at (0,2,0) — so a pressed pill took its background
   from `.is-on` and its colour from here: dark text on a near-black pill.
   `.is-on:hover` then tied on specificity and won on order, which is why the
   text flipped to white under the cursor and nowhere else. The comment above
   already said "unpressed"; the selector did not. Fenced by
   css-state-test-fix6.js §2A/§3. */
.mbpos-epo__choice.is-selected .mbpos-epo__seg:not(.is-on) {
	color: var(--mbpos-color-text, #44403C);
}
/* PRESSED. */
.mbpos-epo__seg.is-on {
	background: linear-gradient(180deg,
		color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 88%, #fff) 0%,
		var(--mbpos-color-primary, #C2410C) 100%);
	border-color: var(--mbpos-color-primary, #C2410C);
	color: var(--mbpos-color-primary-text, #fff);
}
/* [fix2] A pressed segment, hovered. BRIGHTENS the pressed pair rather than
   restating a second hand-matched literal — two colours in two rules is how
   they drift. (0,3,0), above `.is-on` at (0,2,0), and it re-declares colour
   WITH background per fix2's invariant. */
.mbpos-epo__seg.is-on:hover {
	background: linear-gradient(180deg,
		color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 88%, #fff) 0%,
		var(--mbpos-color-primary, #C2410C) 100%);
	border-color: var(--mbpos-color-primary, #C2410C);
	color: var(--mbpos-color-primary-text, #fff);
	filter: brightness(1.08);
}
/* px1's cell, per position. No state rule sets a width on it — a figure that
   appears on interaction is a width change on interaction. */
.mbpos-epo__seg-price {
	font-weight: 500;
	font-variant-numeric: tabular-nums;
}
.mbpos-epo__seg .mbpos-epo__was {
	margin-right: 4px;
	font-weight: 400;
	opacity: .7;
}

/* Removed rows on the cart line (changes-mode "No X") */
.mbpos-cart-addons__item--removed .mbpos-cart-addons__item-label {
	color: var(--mbpos-color-danger-strong, #b32d2e);
	font-weight: 600;
}

/* ── se8: collapsible groups with summary headers ─────────────────────
   st85 rewrite. The header keeps `align-items: baseline` from the base rule
   (title and summary share a true text baseline — the old center override
   floated "Small" above "Size"'s baseline); only the chevron self-centers,
   because a rotated box has no meaningful text baseline. */
.mbpos-epo__group-name {
	cursor: pointer;
	user-select: none;
	-webkit-tap-highlight-color: transparent;
}
.mbpos-epo__group-name:hover {
	background: var(--mbpos-epo-head-bg-hover, #E5E2DC);
}
.mbpos-epo__group-name:active {
	background: var(--mbpos-epo-head-bg-active, #DEDAD3);
}
.mbpos-epo__group-name:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 35%, transparent);
}
.mbpos-epo__summary {
	margin-left: auto;
	font-size: 13px;
	font-weight: 500;
	line-height: 20px;                 /* match the title line so baseline math is exact */
	color: var(--mbpos-color-text-muted, #78716C);
	/* [seg2d] NOT truncated. This was `nowrap` + `ellipsis` + `max-width:55%`,
	   so a pizza with six toppings collapsed to "Tomato Sauce, Mozz…" — and
	   the summary exists precisely so someone can read what is on the pizza
	   WITHOUT expanding. An ellipsis there answers nothing. It now wraps; the
	   heading grows with it, which is fine because the 44px tap target comes
	   from padding and a taller heading is still a heading. If a 20-topping
	   list ever needs a ceiling, `-webkit-line-clamp: 3` is the dial — but
	   pick a ceiling deliberately rather than inheriting one line by default. */
	white-space: normal;
	max-width: 60%;
}
/* Prompt state — a required choice not yet made. Spoken in Primary because
   it's an ACTION the customer must take (v1.20 semantics: action = orange). */
.mbpos-epo__summary.is-prompt {
	color: var(--mbpos-color-primary, #C2410C);
	font-weight: 600;
}
/* "Customise" affordance on collapsed diff groups (Toppings) — "Standard"
   alone is a state word customers can't act on; this names the action.
   Rendered by JS on every group, shown only where it earns its place. */
/* st90: "Customise" is a real chip-button now (was muted "· Customise"
   text — easy to miss, and "Toppings* Standard Customise" read as one
   mushy line on mobile). */
.mbpos-epo__cta::before {
	content: none;
}
.mbpos-epo__cta {
	display: none;
	flex: 0 0 auto;
	font-size: 12px;
	font-weight: 600;
	line-height: 20px;
	padding: 3px 12px;
	/* st93: Appearance-controlled (Product modal & EPO card) — falls back to
	   the st90 look when the skin doesn't emit the tokens. */
	border: 1px solid var(--mbpos-epo-cta-border, var(--mbpos-color-border-strong, rgba(0,0,0,0.25)));
	border-radius: 999px;
	background: var(--mbpos-epo-cta-bg, var(--mbpos-color-surface, #ffffff));
	color: var(--mbpos-epo-cta-text, var(--mbpos-color-heading, #1C1917));
}
/* [hh1] Shown on every collapsed group — with "Standard" and the "choose
   any" hint gone from the bar, this chip is the only thing naming the action. */
.mbpos-epo__group--collapsed .mbpos-epo__cta { display: inline; }
.mbpos-epo__chev {
	flex: 0 0 auto;
	align-self: center;                /* rotated box — centring beats baseline */
	width: 10px;
	height: 10px;
	border-right: 2px solid var(--mbpos-color-text-muted, #78716C);
	border-bottom: 2px solid var(--mbpos-color-text-muted, #78716C);
	transform: rotate(45deg) translateY(-2px);   /* open: pointing down */
	transition: transform .2s ease;
}
.mbpos-epo__group--collapsed .mbpos-epo__chev { transform: rotate(-45deg) translate(-1px, 1px); }
.mbpos-epo__group--collapsed .mbpos-epo__choices,
.mbpos-epo__group--collapsed .mbpos-epo__error { display: none; }
.mbpos-epo__group--error .mbpos-epo__summary { color: var(--mbpos-color-danger, #B91C1C); }

/* ── Combo shared EPO: inline layout (st81) ─────────────────────────
   In the combo's shared section (e.g. Size), the summary ("Small")
   should sit inline beside the label — not pushed to the far right.
   Reads as "Size · Small" in one left-aligned sweep. Scoped with
   [data-mbpos] to beat any theme legend/fieldset overrides. */
[data-mbpos] .mbpos-combo__shared .mbpos-epo__summary {
	margin-left: 0;
}
[data-mbpos] .mbpos-combo__shared .mbpos-epo__summary::before {
	content: '\00B7\00A0';
	color: var(--mbpos-color-text-muted, #888);
}
/* st85: the old `align-items: center` override here was the "Small floats
   above Size" bug — it beat the baseline rule on specificity (0,3,0 vs
   0,2,0) and vertically centred two different font sizes against each
   other. Baseline comes from the base/scoped rules; here we only pin the
   left-aligned inline reading and push the chevron to the far edge so the
   header scans the same as non-shared groups. */
[data-mbpos] .mbpos-combo__shared .mbpos-epo__group-name {
	justify-content: flex-start;
}
[data-mbpos] .mbpos-combo__shared .mbpos-epo__chev {
	margin-left: auto;
}
/* In the inline reading a prompt renders "Size · Select Size" — hide the
   separator dot so it reads "Size  Select Size" with the prompt colour
   carrying the distinction. */
[data-mbpos] .mbpos-combo__shared .mbpos-epo__summary.is-prompt::before {
	content: '';
}

/* ── Customise indicator on product cards (moved here ca2) ───────────────
   Lives in this frontend-loaded sheet (global-style.css is admin-only, so
   the badge was invisible on the live POS page). The renderer appends the
   badge to .grid-tile__card — a Bricks class with no guaranteed positioning
   — so own the one declaration it depends on or the absolute badge drifts
   off-card. */
.grid-tile__card { position: relative; }

.mbpos-card-customize {
	position: absolute;
	bottom: 8px;
	right: 8px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 24px;
	height: 24px;
	border-radius: 50%;
	/* sk2: was a fixed white chip + text-colour icon — on a dark theme
	   (light text) that rendered white-on-white. Surface + heading stay
	   paired in every scheme. */
	background: var(--mbpos-color-surface, rgba(255,255,255,.92));
	color: var(--mbpos-color-heading, #444);
	opacity: .95;
	box-shadow: 0 1px 3px rgba(0,0,0,.25);
	pointer-events: none; /* clicks pass through to the card */
	z-index: 2;
}

/* ── Shared "ask once" combo options (e.g. Size) ─────────────────────────
   Rendered once at the top of the combo slot list (above the halves). The
   inner .mbpos-epo carries its own styling; this just sets it off from the
   slot rows below with a little space and a hairline divider. */
.mbpos-combo__shared {
	margin-bottom: 5px;
	padding-bottom: 2.5px;
	border-bottom: 1px solid rgba(0,0,0,.08);
}

/* ── Theme isolation: EPO controls (st82) ──────────────────────────────
   Themes target <legend>, <label>, <input> with bare-tag selectors
   (text-align:center, display:inline, position:static). The :where()
   button/input reset in mbpos-pos-layout.css doesn't cover <legend> or
   <label>, so these need their own [data-mbpos] scoping. */

/* [stk1] STICKY, so a long topping list always says which group you are in.
   The group heading is the natural candidate: it is already a filled 44px bar
   with its own background, so it needs no restyling to survive being lifted
   out of the flow visually. The SECTION headings are deliberately NOT sticky —
   they sit inset in their own border, and a heading cannot be both inset in a
   border and floating at the top of the scroller. Two stacked sticky bars
   would also cost ~70px of permanent chrome in a modal that is ~500px tall on
   a phone. Cheap: sticky is a compositor job, no JS, no scroll listener. */
[data-mbpos] .mbpos-epo__group-name {
	position: sticky;
	top: 0;
	z-index: 2;
	display: flex;
	flex-wrap: wrap;            /* [seg2d] a full summary drops to its own line */
	align-items: baseline;      /* title + summary share a true text baseline */
	gap: 8px;
	/* [fix4] st92's inset lives HERE now, because this is the rule that wins.
	   Option rows sit ~4px in; a full-bleed header overhangs their borders and
	   reads as misaligned. VISIBLE CHANGE on arrival — st92 shipped this
	   intent and never once applied it. To revert, set both back to
	   `width: 100%` / `margin: 0 0 var(--mbpos-space-2xs, 8px)`. */
	width: calc(100% - 2 * var(--mbpos-epo-head-inset, 4px));
	text-align: left;
	font: inherit;
	font-size: var(--mbpos-epo-head-size, var(--mbpos-font-size-base, 14px));
	font-weight: var(--mbpos-epo-head-weight, 600);
	line-height: 20px;
	color: var(--mbpos-epo-head-color, var(--mbpos-color-heading, #1C1917));
	margin: 0 var(--mbpos-epo-head-inset, 4px) var(--mbpos-space-2xs, 8px);
	padding: 12px var(--mbpos-space-s, 14px);   /* 12+20+12 = 44px tap target */
	background: var(--mbpos-epo-head-bg, #EFEDE8);
	border: none;
	border-radius: var(--mbpos-radius-s, 6px);
	box-sizing: border-box;
	cursor: pointer;
	user-select: none;
	-webkit-tap-highlight-color: transparent;
	transition: background-color .15s ease, box-shadow .15s ease;
}
[data-mbpos] .mbpos-epo__group-name:hover {
	background: var(--mbpos-epo-head-bg-hover, #E5E2DC);
}
[data-mbpos] .mbpos-epo__group-name:active {
	background: var(--mbpos-epo-head-bg-active, #DEDAD3);
}
[data-mbpos] .mbpos-epo__group-name:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 35%, transparent);
}
/* Error state re-declared at scoped specificity so it beats the hover rule
   above (both (0,3,0); this comes later in source). */
[data-mbpos] .mbpos-epo__group--error .mbpos-epo__group-name,
[data-mbpos] .mbpos-epo__group--error .mbpos-epo__group-name:hover {
	background: var(--mbpos-color-danger-subtle, rgba(185,28,28,0.08));
	box-shadow: inset 3px 0 0 var(--mbpos-color-danger, #B91C1C);
}

[data-mbpos] .mbpos-epo__choice {
	position: relative;
	display: block;
	text-align: left;
	font: inherit;
	color: inherit;
	line-height: 1.4;
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
}

[data-mbpos] .mbpos-epo__input {
	position: absolute;
	opacity: 0;
	width: 1px;
	height: 1px;
	margin: 0;
	pointer-events: none;
}

/* ══════════════════════════════════════════════════════════════════════
   st86 — GUIDED FLOW
   ----------------------------------------------------------------------
   One element per modal carries .mbpos-step-active: a steady 2px primary
   outline ring (outline, deliberately — it never fights an element's own
   box-shadows) plus TWO pulse cycles on arrival, then still. Perpetual
   pulsing reads as an error state and is a vestibular-accessibility
   problem; two cycles draw the eye, the steady ring then says "you are
   here" without shouting. prefers-reduced-motion keeps the ring, drops
   the motion.
   ══════════════════════════════════════════════════════════════════════ */

@keyframes mbpos-step-pulse {
	0%   { box-shadow: 0 0 0 0   color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 40%, transparent); }
	70%  { box-shadow: 0 0 0 12px color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 0%, transparent); }
	100% { box-shadow: 0 0 0 0   transparent; }
}

/* Group spotlight rides the header chip, not the whole fieldset — the bar
   is the tappable thing, and ringing an expanded list of ten toppings
   reads as "everything is wrong". */
/* [fix4] The Add button used to ride in this list and then have its
   outline-offset and animation overridden by its own block below — so this
   list declared two values the Add button never took. Split out: each rule
   now states only what its elements actually get. */
[data-mbpos] .mbpos-epo__group.mbpos-step-active > .mbpos-epo__group-name,
[data-mbpos] .mbpos-combo__slot.mbpos-step-active,
[data-mbpos] .mbpos-combo__opts-done.mbpos-step-active {
	outline: 2px solid color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 55%, transparent);
	outline-offset: 2px;
	animation: mbpos-step-pulse .9s ease-out 2;
}

/* The Add button gets its own, more prominent arrival: a scale breathe on
   top of a wider glow (st86.1 — the generic ring pulse was too quiet on a
   button that's already saturated). Three cycles, then still; the is-ready
   glow carries the steady state. Paired with a single 15ms haptic tick on
   Android when the order completes. */
@keyframes mbpos-add-pulse {
	0%   { transform: scale(1);
	       box-shadow: 0 0 0 0    color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 55%, transparent); }
	45%  { transform: scale(1.03);
	       box-shadow: 0 0 0 14px color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 0%, transparent); }
	100% { transform: scale(1);
	       box-shadow: 0 0 0 0    transparent; }
}
[data-mbpos] .mbpos-products-detail__add.mbpos-step-active {
	outline: 2px solid color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 55%, transparent);
	outline-offset: 3px;   /* wider than the generic ring — st86.1 */
	animation: mbpos-add-pulse .8s ease-out 3;
}
[data-mbpos] .mbpos-products-detail__add.is-ready {
	box-shadow: 0 4px 14px color-mix(in srgb, var(--mbpos-color-primary, #C2410C) 35%, transparent),
	            inset 0 1px 0 rgba(255,255,255,0.14);
}

@media (prefers-reduced-motion: reduce) {
	[data-mbpos] .mbpos-epo__group.mbpos-step-active > .mbpos-epo__group-name,
	[data-mbpos] .mbpos-combo__slot.mbpos-step-active,
	[data-mbpos] .mbpos-combo__opts-done.mbpos-step-active,
	[data-mbpos] .mbpos-products-detail__add.mbpos-step-active {
		animation: none;
	}
	[data-mbpos] .mbpos-epo__control::after,
	[data-mbpos] .mbpos-epo__chev {
		transition: none;
	}
}

/* Picker prompt — guidance by language: "Choose your First Half". Same
   prompt voice (primary, 600) as the "Select Size" summary state. */
[data-mbpos] .mbpos-combo__picker-prompt {
	font-size: 13px;
	font-weight: 600;
	color: var(--mbpos-color-primary, #C2410C);
	margin: var(--mbpos-space-2xs, 8px) 0 var(--mbpos-space-xs, 12px);
}

/* Slot-list progress line — "2 of 3 selected". The slot ticks are the real
   progress UI; this is the glanceable summary beside the Add bar. */
[data-mbpos] .mbpos-combo__progress {
	display: block;
	font-size: 12.5px;
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	color: var(--mbpos-color-text-muted, #78716C);
	margin-top: var(--mbpos-space-2xs, 8px);
}
[data-mbpos] .mbpos-combo__progress:empty { display: none; }
[data-mbpos] .mbpos-combo__progress.is-complete {
	color: var(--mbpos-color-success, #15803D);
}

/* ------------------------------------------------------------------------
   ce1 — edit-mode notice
   A choice 86'd between add and edit is baked out of products.json, so it
   has no row in this form to badge. The notice names it instead. Persistent,
   not a toast: it is a standing condition the customer must resolve before
   the server will accept the edit.
   ------------------------------------------------------------------------ */
.mbpos-epo__notice {
	margin:        0 0 var(--mbpos-space-s, 12px);
	padding:       10px 12px;
	font-size:     13px;
	line-height:   1.35;
	color:         var(--mbpos-color-danger, #B91C1C);
	background:    var(--mbpos-color-danger-bg, rgba(185, 28, 28, .07));
	border:        1px solid var(--mbpos-color-danger, #B91C1C);
	border-radius: var(--mbpos-radius-s, 6px);
}

/* ════════════════════════════════════════════════════════════════════
   ce3 — the edit affordance on the cart's addons block.

   WHY IT LIVES HERE, NOT IN mbpos-pos-layout.css:
   that stylesheet is enqueued ONLY by the [mbpos_pos_layout] shortcode. A
   Bricks POS template never loads it — and never loads its :root tokens
   either. This sheet is enqueued globally by MBPOS_Enqueue, alongside the
   .mbpos-cart-addons rules it decorates. Markup emitted by the plugin's own
   renderers must be styled in a globally-enqueued sheet, or it ships
   unstyled on Bricks. (It did: the overlay rendered inline as a second
   pencil beside the resting one.) EVERY var() below therefore carries a
   literal fallback — the tokens are absent on Bricks by design.

   THE PENCIL RESTS. It is visible on every device, always. The OVERLAY is
   the hover enhancement, behind @media (hover: hover) — customers order
   from phones, where hover does not exist and sticky-hover would turn the
   first tap into a reveal instead of an action.

   The overlay is translucent, not opaque: the customer's own choices stay
   legible underneath, so the hover state reads as "you may change this"
   rather than blanking the information they are deciding against.

   Colour is --mbpos-color-primary (near-black since st89, Appearance-
   overridable). Never --mbpos-color-danger (that means "this line is
   broken" — ce2 owns it) and never success-green (that means "done").
   ════════════════════════════════════════════════════════════════════ */

.mbpos-cart-item__addons--editable {
	position:      relative;
	/* [ce8] `isolation: isolate` sat here for ce7b's z-index:-1 overlay and
	   went with it — there is no negative-z child left to contain. */
	display:       block;
	padding-left:  var(--mbpos-edit-gutter);
	border-radius: var(--mbpos-radius-s, 6px);
	cursor:        pointer;
	transition:    background-color .12s ease;
	-webkit-tap-highlight-color: transparent;
}
.mbpos-cart-item__addons--editable:focus-visible {
	outline:        2px solid var(--mbpos-color-primary, #171717);
	outline-offset: 2px;
}
.mbpos-cart-item__addons--editable.is-busy { cursor: progress; opacity: .6; }

/* [ce3.2] ONE pencil, at ONE coordinate. It stacks ABOVE the overlay (z-index)
   rather than the overlay carrying a duplicate: on hover the icon does not move
   a pixel, because it is the same element. GUTTER and PENCIL_TOP below are that
   coordinate; the overlay's label is positioned FROM them, never independently. */
.mbpos-cart-item__addons--editable {
	--mbpos-edit-gutter: 24px;   /* the pencil's column, left of the rule */
	--mbpos-edit-top:    7px;    /* the pencil's baseline */
	--mbpos-edit-rule:   2px;    /* .mbpos-cart-addons' left rule — see below */
	/* [ce8] The chip's ink is inlined on the one rule that draws it — no
	   token to keep in sync with a second reader that does not exist. */
}

.mbpos-cart-item__addons-pencil {
	position:    absolute;
	/* [ce8] A 20px CHIP, sized and placed at rest and never on hover. Only the
	   chip's ink changes when the pointer arrives, so the icon cannot move —
	   ce3.2's rule, and the reason the box is declared here rather than grown
	   later. The offsets are the old 2px/7px pulled back by 3px so the svg
	   still sits on the first summary row's optical line inside its new box. */
	left:        1px;
	top:         calc(var(--mbpos-edit-top) - 3px);
	width:       20px;
	height:      20px;
	display:     inline-flex;
	align-items: center;
	justify-content: center;
	border-radius: 50%;
	background:  transparent;
	line-height: 0;
	/* [ce3.3] The pencil rests in the SAME ink it hovers in. Muted grey read as
	   decoration, not a control — customers did not see it as tappable. Only
	   the opacity lifts on hover, so the colour never "changes", it just
	   settles. Applies on every surface, drawer and cart page alike. */
	color:       var(--mbpos-color-primary, #171717);
	opacity:     .72;
	z-index:     2;                       /* [ce8] above the summary: never occluded, never moved */
	pointer-events: none;                 /* the block beneath owns the click */
	transition:  background-color .12s ease, opacity .12s ease;
}

/* [ce8] The overlay element is gone — see pos-cart-render.js for why. What
   marked the region is now the chip behind the pencil, which is both louder
   than any of the three region treatments and incapable of touching what the
   customer is reading. */

/* Press feedback everywhere; the chip only where a pointer can hover. */
.mbpos-cart-item__addons--editable:active .mbpos-cart-item__addons-pencil { opacity: 1; }
@media (hover: hover) and (pointer: fine) {
	/* [ce5 W13] The block itself takes NO hover background. The old
	   `background-color: rgba(0,0,0,.02)` here tinted the WHOLE block —
	   pencil gutter and rule included — contradicting the ce3.5 doctrine
	   below. cart-edit-test-ce5.js asserts no `background` property ever
	   returns to this selector.

	   [ce8] Hover now does exactly two things, both to the pencil and neither
	   to the customer's own words: the icon settles to full ink, and a chip
	   appears behind it. GEOMETRY IS UNTOUCHED — the box was already 20px at
	   rest, so nothing moves, grows or reflows. That is the ce3.2 invariant,
	   and it is what a `transform: scale()` here would quietly break. */
	.mbpos-cart-item__addons--editable:hover .mbpos-cart-item__addons-pencil {
		opacity: 1;
		background-color: color-mix(in srgb, var(--mbpos-color-primary, #171717) 13%, transparent);
	}
	/* [ce3.5] The left rule does NOT change colour on hover. It is the block's
	   frame, not a state indicator — inking it made the row look selected, and
	   it competed with the pencil for the "something happened" signal. */
}
@media (prefers-reduced-motion: reduce) {
	.mbpos-cart-item__addons--editable,
	.mbpos-cart-item__addons-pencil { transition: none; }
}

/* ce2: a seeded combo edit whose stored pick/choice died since add marks the
   slot row in error and leaves it unstamped — the customer's next tap is the
   fix. .mbpos-combo__slot--error (the modifier validate() writes) is styled
   above; this adds the tint. Lives here for the same enqueue reason as ce3. */
.mbpos-combo__slot--pick.mbpos-combo__slot--error {
	background: color-mix(in srgb, var(--mbpos-color-danger, #B91C1C) 6%, transparent);
}

/* ── [seg2a/seg2b] Derived sections + the pressed tick ───────────────────
   Scoped at (0,2,0) per fix7's tier: components sit above the reset layer,
   never level with it. */

/* A LIGHT DIVIDER, not a second collapsible tier. The group heading is
   already a 44px collapse control, and stacking two folds is exactly how
   hh2sf broke — Peter clicked Customise and saw nothing. */
/* [seg2d] The section reads as a BOX with its name in the border, so the
   included toppings and the paid ones are visibly two things rather than one
   list with a caption. No background shade: the seg cards are already white on
   white and a third surface tone muddies them — the border alone separates. */
[data-mbpos] .mbpos-epo__section-body {
	/* [hov1-a] ONE writer for the box's inner gutter. The rows below bleed out
	   to the border by pulling exactly this much back, so the two numbers must
	   never be typed twice. */
	--mbpos-epo-section-pad: 8px;
	margin: 14px 0 0;
	padding: 14px var(--mbpos-epo-section-pad) var(--mbpos-epo-section-pad);
	border: 1px solid var(--mbpos-color-border, #E3E0DA);
	border-radius: var(--mbpos-radius-s, 6px);
}
[data-mbpos] .mbpos-epo__section-body:first-child {
	margin-top: 0;
}
/* Sits IN the border rather than under it: pulled up by its own height and
   given the surface colour so the border passes behind the words, not
   through them. */
/* [tot1] The heading is now a row: name on the left, this section's subtotal
   on the right. The total cell renders in EVERY state — empty when the section
   adds nothing — and reserves its width, because a figure that appears when
   you tick your first topping is the xtra2 shift by another route. Same rule
   px1 applies to the per-row price cell, one level up. */
/* [tot2] The group figure rides the STICKY bar, so the running cost stays on
   screen once the list scrolls past — which is the only reason to put a number
   in a heading at all. Reserved width and always-rendered for the same reason
   as the section cells: a sticky bar that changes size mid-scroll reflows
   everything under it. */
/* [sum1] The summary is for the COLLAPSED state and only that. It wraps since
   seg2d, so on an expanded group it made the sticky bar two or three lines of
   permanent chrome — and while the group is open the summary is redundant
   anyway, because the choices themselves are on screen. Collapsed it is the
   whole point; expanded it is noise. */
[data-mbpos] .mbpos-epo__group:not(.mbpos-epo__group--collapsed) .mbpos-epo__summary {
	display: none;
}

[data-mbpos] .mbpos-epo__group-total {
	min-width: 52px;
	margin-left: 8px;
	text-align: right;
	font-variant-numeric: tabular-nums;
	font-weight: 700;
	color: inherit;
}
[data-mbpos] .mbpos-epo__section {
	display: inline-flex;
	align-items: baseline;
	gap: 10px;
	margin: -22px 0 6px 4px;
	padding: 2px 8px;
	/* [def1] A tint rather than plain surface. It still has to be OPAQUE, or
	   the border it sits on would run through the words — the surface colour
	   was doing that job and the tint keeps doing it while giving Peter the
	   definition he asked for. color-mix against surface rather than a literal
	   so it follows the venue's skin instead of pinning a grey. */
	background: color-mix(in srgb, var(--mbpos-color-border, #E3E0DA) 55%, var(--mbpos-color-surface, #FFFFFF));
	border-radius: var(--mbpos-radius-s, 6px);
	font-size: 12px;
	font-weight: 700;
	letter-spacing: 0.4px;
	text-transform: uppercase;
	color: var(--mbpos-color-text-muted, rgba(29,28,27,0.6));
}

/* The tick occupies its slot in EVERY segment and is revealed by opacity.
   Presence-toggling would change the pill's width on press — the xtra2
   shift by a new route, and the reason px1's price cell renders empty
   rather than disappearing. */
/* [seg2d] OUT OF FLOW. seg2b reserved the tick's slot in every segment, which
   kept the width stable but left an empty gap on the left of every unpressed
   pill — the label sat visibly off-centre. Peter proposed a checkbox glyph to
   fill it; a checkbox is the wrong signal (these are role="radio" in a
   radiogroup — exactly one level per topping — and a checkbox says "tick as
   many as you like"), and a radio dot would put ~48 marks on a 16-topping
   modal. Absolute positioning solves it without a second glyph: the label
   centres across the WHOLE pill in every state, and the tick lives in the
   horizontal gutter the padding already provides. Nothing moves on press,
   which is still the invariant. */
[data-mbpos] .mbpos-epo__seg-tick {
	position: absolute;
	left: 6px;
	top: 50%;
	transform: translateY(-50%);
	font-size: 10px;
	line-height: 1;
	opacity: 0;
}
[data-mbpos] .mbpos-epo__seg.is-on .mbpos-epo__seg-tick {
	opacity: 1;
}

/* ── [box1] One level of boxing, not two ─────────────────────────────────
   Inside a section box the per-choice card drops its own border and becomes a
   hairline-separated row. The card border was doing the "these belong
   together" job that the section box now does better, and two nested 1px greys
   read as boxes-in-boxes. Only the WIDTHS and the radius are touched —
   border-COLOR is left alone so `.is-selected` still has something to colour,
   which is why the selected row now reads as a stronger rule beneath it rather
   than losing its state. */
[data-mbpos] .mbpos-epo__section-body .mbpos-epo__choice.mbpos-epo__choice--seg {
	border-width: 0 0 1px;
	border-radius: 0;
	background: transparent;
	/* [hov1-a] The row BLEEDS to the section border and pays the gutter back as
	   its own padding. Peter, on the hover tint: "the background could be closer
	   to the border, right now it is butting up to the text." Both halves of
	   that are this one geometry — the row box used to end 2px from the label,
	   so the tint had nowhere to go and the hairline stopped short of the box.
	   The label does not move: what it loses in margin it gains in padding, so
	   nothing reflows and the tint simply has room to exist. */
	margin-left: calc(-1 * var(--mbpos-epo-section-pad, 8px));
	margin-right: calc(-1 * var(--mbpos-epo-section-pad, 8px));
	padding-left: var(--mbpos-epo-section-pad, 8px);
	padding-right: var(--mbpos-epo-section-pad, 8px);
}
[data-mbpos] .mbpos-epo__section-body .mbpos-epo__choice.mbpos-epo__choice--seg:last-child {
	border-width: 0;
}
