/**
 * Class Timetable (VX).
 *
 * Everything is scoped under `.vxb-classes` and driven by the shared `--vxb-*` master
 * palette (set by the widget's Style controls / presets), so a site's theme or Elementor
 * Kit can't repaint it by accident. Colours derive from the palette rather than fixed hex,
 * so all five presets stay contrast-safe; fonts deliberately inherit.
 *
 * The one exception is each card's left bar, which is set inline from the CLASS's stored
 * colour — that's identity, not theming, and it must match the vendor's editor exactly.
 */

.vxb-classes[v-cloak] { display: none; }

:where( .vxb-classes button ) { border: 0; }

/* Voxel's button classes, which the Button style controls target. */
.vxb-classes .ts-btn-2 {
	background: var( --vxb-accent );
	border: 1px solid var( --vxb-accent );
	color: var( --vxb-on-accent );
}
.vxb-classes .ts-btn-1 {
	background: var( --vxb-bg );
	border: 1px solid var( --vxb-border );
	color: var( --vxb-text );
}

/* ── Base variables = the "Minimal" preset. Elementor's controls override these. ── */
.vxb-classes {
	--vxb-text: #1f2937;
	--vxb-muted: #6b7280;
	--vxb-border: #e5e7eb;
	--vxb-bg-soft: #f9fafb;
	--vxb-bg: #ffffff;
	--vxb-accent: var( --ts-accent-1, #1f7a54 );
	--vxb-on-accent: #ffffff;
	--vxb-radius: 12px;
	/* Credits get their OWN colour, distinct from the booking accent, so "Use 1 credit" never
	   looks like the cash Book button. Deliberately set once (not per preset): a credit is a
	   currency, and one consistent honey across every theme reads as such. */
	--vxb-credit: #c67c1a;
	--vxb-on-credit: #ffffff;

	/* Wired to the Status colour controls: Bookable / Nearly full / Full-closed. */
	--vxb-completed: #1e7e45;
	--vxb-pending: #b45309;
	--vxb-canceled: #b42318;

	color: var( --vxb-text );
	font-size: 0.9375rem;
	line-height: 1.5;

	/* Makes the widget its own layout context, so the narrow-column rules at the bottom of
	   this file key off THIS element's width rather than the phone's. Dropped into a 380px
	   Elementor column on a 1440px desktop, a viewport media query never fires and the
	   customer gets the desktop row crushed to a third of its width — which is exactly what
	   used to happen. Safe to rely on: this file already uses color-mix(), which landed in
	   every browser LATER than container queries did, so anything that can render the
	   widget at all can do this. */
	container-type: inline-size;
}

/* ── The other four presets. The preset control writes `vxb-preset-{key}` on the widget
   wrapper; WITHOUT these blocks the widget silently stays on Minimal, which is how you get
   white cards on a dark page. Values match the other VX widgets so a site themed once looks
   themed everywhere. ── */
.vxb-preset-soft .vxb-classes {
	--vxb-accent: #1d9e75; --vxb-bg: #fbfaf7; --vxb-bg-soft: #f3efe8;
	--vxb-text: #33302a; --vxb-muted: #8c8579; --vxb-border: #ece6db; --vxb-radius: 16px;
}
.vxb-preset-bold .vxb-classes {
	--vxb-accent: #534ab7; --vxb-bg: #ffffff; --vxb-bg-soft: #f1f0fb;
	--vxb-text: #1c1830; --vxb-muted: #6f6a86; --vxb-border: #e2e0f0; --vxb-radius: 18px;
}
.vxb-preset-midnight .vxb-classes {
	--vxb-accent: #8f86e6; --vxb-on-accent: #14121f; --vxb-bg: #1b1d24; --vxb-bg-soft: #23262f;
	--vxb-text: #eef0f5; --vxb-muted: #9aa1b1; --vxb-border: #313542;
	--vxb-completed: #5dcaa5; --vxb-pending: #efaf52; --vxb-canceled: #e86a6a; --vxb-radius: 12px;
}
.vxb-preset-activity-rush .vxb-classes {
	--vxb-accent: #c0fa1e; --vxb-on-accent: #121416; --vxb-bg: #1c1e22; --vxb-bg-soft: #25272d;
	--vxb-text: #fafafa; --vxb-muted: #a1a4aa; --vxb-border: #30333a;
	--vxb-completed: #5dcaa5; --vxb-pending: #efaf52; --vxb-canceled: #f0616a; --vxb-radius: 12px;
}

.vxb-classes .vxb-ct-head h2 {
	margin: 0 0 14px !important;
	font-size: 1.125rem !important;
	line-height: 1.3;
	color: var( --vxb-text ) !important;
}

.vxb-ct-note {
	margin: 0;
	padding: 18px 4px;
	color: var(--vxb-muted);
	font-size: 0.9375rem;
}

.vxb-ct-note-bad { color: var(--vxb-canceled); }

/* ---------------------------------------------------------------------
 * Day strip
 * ------------------------------------------------------------------- */

/* Capped rather than full-width. The spacer between the arrows makes this row as wide as it
   is allowed to be, so on a wide screen the two arrows ended up ~1000px apart, at opposite
   edges of the page, with nothing between them — they read as page furniture instead of as
   controls for the strip below. Bounding the row pulls them into one cluster over the first
   chips, next to the dates they page. */
.vxb-ct-nav {
	display: flex;
	align-items: center;
	gap: 8px;
	margin-bottom: 8px;
	/* Wide enough for the two arrows, the date range they page, and the Today link — but
	   still a tidy cluster rather than a row spanning a desktop-wide widget. */
	max-width: 340px;
}

.vxb-ct-spacer { flex: 1; }

.vxb-classes .vxb-ct-arrow {
	flex: 0 0 auto;
	width: 32px !important;
	height: 32px !important;
	min-height: 0 !important;
	padding: 0 !important;
	border: 1px solid var( --vxb-border ) !important;
	border-radius: var( --vxb-radius, 8px ) !important;
	background: transparent !important;
	color: var( --vxb-text ) !important;
	font-size: 1.125rem !important;
	line-height: 1 !important;
	cursor: pointer;
}

.vxb-classes .vxb-ct-arrow:hover:not([disabled]) { border-color: var( --vxb-accent ) !important; }

.vxb-classes .vxb-ct-arrow[disabled] {
	opacity: .35;
	cursor: not-allowed;
	pointer-events: none;
}

.vxb-classes .vxb-ct-today {
	flex: 0 0 auto;
	white-space: nowrap;
	font-size: 0.85rem;
	font-weight: 600;
	color: var( --vxb-accent ) !important;
	text-decoration: none;
	cursor: pointer;
}

.vxb-classes .vxb-ct-days {
	display: flex;
	gap: 6px;
	overflow-x: auto;
	/* Room for the today dot, which sits just under a chip. This is a scroll container, so
	   the dot has to land inside the padding — anything past it would be clipped. */
	padding-bottom: 10px;
	margin-bottom: 14px;
	/* Momentum scroll on touch without a visible bar eating vertical space. */
	scrollbar-width: thin;
}

/* The native bar is chunky enough to read as a page element rather than part of the strip. */
.vxb-classes .vxb-ct-days::-webkit-scrollbar { height: 4px; }
.vxb-classes .vxb-ct-days::-webkit-scrollbar-track { background: transparent; }
.vxb-classes .vxb-ct-days::-webkit-scrollbar-thumb {
	background: var(--vxb-border);
	border-radius: 4px;
}

.vxb-classes .vxb-ct-day {
	position: relative;
	flex: 0 0 auto;
	min-width: 62px;
	padding: 8px 10px;
	border-radius: var(--vxb-radius, 8px);
	border: 1px solid var(--vxb-border);
	background: transparent;
	color: var(--vxb-text);
	cursor: pointer;
	text-align: center;
	line-height: 1.3;
	transition: border-color .15s ease, background .15s ease;
}

.vxb-classes .vxb-ct-day:hover { border-color: var(--vxb-accent); }

/* Filled rather than tinted: this is the widget's primary state and a 12% wash was leaving
   it to compete with the hover border. Colours are the palette's own accent pair. */
.vxb-classes .vxb-ct-day.on {
	border-color: var(--vxb-accent);
	background: var(--vxb-accent);
}

/* Today, once you've paged away from it. Sits under the chip so it reads on a filled one too. */
.vxb-classes .vxb-ct-day.today:after {
	content: "";
	position: absolute;
	left: 50%;
	bottom: -6px;
	transform: translateX(-50%);
	width: 4px;
	height: 4px;
	border-radius: 50%;
	background: var(--vxb-accent);
}

/* An empty day stays selectable — a closed Thursday is information, not an absence. */
.vxb-classes .vxb-ct-day.empty { opacity: .55; }

/* Upper-right mark: this day has a class matching the active filter. Only rendered while a
   filter is set (see day.match), so it never competes with the normal count line. */
.vxb-ct-day-mark {
	position: absolute;
	top: 5px;
	right: 5px;
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: var(--vxb-accent);
}

/* On the selected (accent-filled) chip the accent dot would vanish — flip it to the
   accent's own foreground so it stays visible. */
.vxb-classes .vxb-ct-day.on .vxb-ct-day-mark { background: var(--vxb-on-accent); }

.vxb-ct-dow { display: block; font-size: 0.85rem; color: var(--vxb-muted); }
.vxb-ct-dom { display: block; font-size: 0.9375rem; font-weight: 600; }
.vxb-ct-cnt { display: block; font-size: 0.85rem; color: var(--vxb-muted); margin-top: 2px; }

/* On a filled chip every line flips to the accent's own foreground — including the day
   number, which inherits from .vxb-ct-day. */
.vxb-classes .vxb-ct-day.on,
.vxb-classes .vxb-ct-day.on .vxb-ct-dow,
.vxb-classes .vxb-ct-day.on .vxb-ct-cnt { color: var(--vxb-on-accent); }

/* ---------------------------------------------------------------------
 * Filters (class / instructor)
 *
 * The widget root deliberately carries no `ts-form`, so the theme doesn't style these
 * selects — which means we must, fully, or a bare <select> renders in the browser default.
 * Every legibility property is forced so neither the theme nor the Elementor Kit can repaint
 * them. Colours come from the palette, like everything else here.
 * ------------------------------------------------------------------- */

.vxb-ct-filters {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 10px;
	margin-bottom: 16px;
}

.vxb-ct-filter {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	margin: 0;
	font-size: 0.8125rem;
	color: var(--vxb-muted);
}

.vxb-ct-filter-k { flex: 0 0 auto; }

.vxb-classes .vxb-ct-filter-sel {
	flex: 0 1 auto;
	max-width: 220px;
	margin: 0 !important;
	padding: 7px 30px 7px 12px !important;
	border: 1px solid var(--vxb-border) !important;
	border-radius: var(--vxb-radius, 8px) !important;
	background: var(--vxb-bg) !important;
	color: var(--vxb-text) !important;
	font-size: 0.8125rem !important;
	line-height: 1.3 !important;
	height: auto !important;
	min-height: 0 !important;
	cursor: pointer;
	/* Kill the theme's native-control reset so our own caret shows, and draw one. */
	-webkit-appearance: none;
	-moz-appearance: none;
	appearance: none;
	background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E" );
	background-repeat: no-repeat;
	background-position: right 10px center;
}

.vxb-classes .vxb-ct-filter-sel:focus {
	outline: none;
	border-color: var(--vxb-accent) !important;
}

.vxb-classes .vxb-ct-filter-clear {
	flex: 0 0 auto;
	margin: 0 !important;
	padding: 0 !important;
	border: 0 !important;
	background: transparent !important;
	color: var(--vxb-accent) !important;
	font-size: 0.85rem !important;
	text-decoration: underline;
	cursor: pointer;
	width: auto !important;
	min-height: 0 !important;
	height: auto !important;
}

/* ---------------------------------------------------------------------
 * Agenda: time gutter + cards
 * ------------------------------------------------------------------- */

/* The gutter has to be a fixed width, not `auto`: each group is its own grid, so an auto
   column would size to that group's own label and the times would stagger down the page.
   58px fits "16:00" at semibold — the old 52px was a pixel short of it. A 12-hour site needs
   room for "10:00 AM", so the agenda widens itself rather than wrapping the label. */
.vxb-ct-agenda { --vxb-ct-gut: 58px; }
.vxb-ct-agenda.vxb-ct-12h { --vxb-ct-gut: 76px; }

.vxb-ct-group {
	display: grid;
	grid-template-columns: var( --vxb-ct-gut, 58px ) minmax(0, 1fr);
	gap: 12px;
	margin-bottom: 10px;
}

.vxb-classes .vxb-ct-time {
	position: relative;
	margin: 0 !important;
	/* Left padding clears the rail + dot; the top padding centres the label on the card's
	   first line, which is what the dot is aligned to as well. */
	padding: 13px 0 0 18px;
	font-size: 0.8125rem !important;
	font-weight: 600;
	line-height: 1.3;
	color: var( --vxb-text ) !important;
}

.vxb-classes .vxb-ct-time.dim { opacity: .5; }

/* The rail runs between the dots — starting at the first and stopping at the last, rather
   than running off into empty space at either end. `bottom: -10px` bridges the gap to the
   next group so the line reads as continuous. */
.vxb-ct-rail {
	position: absolute;
	left: 4px;
	top: 0;
	bottom: -10px;
	width: 1px;
	background: var( --vxb-border );
}

.vxb-ct-group:first-child .vxb-ct-rail { top: 22px; }
.vxb-ct-group:last-child .vxb-ct-rail { bottom: auto; height: 22px; }
.vxb-ct-group:only-child .vxb-ct-rail { display: none; }

/* Centred on the rail (its 9px straddles the line at x=4.5) and on the class name's first
   line. Solid, so the rail passes behind it without needing a ring in the page's colour —
   which this widget has no way to know. */
.vxb-ct-dot {
	position: absolute;
	left: 0;
	top: 18px;
	width: 9px;
	height: 9px;
	border-radius: 50%;
	background: var( --vxb-muted );
}

.vxb-ct-cards { display: flex; flex-direction: column; gap: 8px; }

/* The class's own colour arrives inline from cardStyle() as both the left border and
   --vxb-ct-cc. The wash is that colour at 7%, faded out by the midpoint — enough to make a
   class one recognisable object across the day without tinting the text it sits under. */
.vxb-ct-card {
	border: 1px solid var(--vxb-border);
	border-left: 3px solid var(--vxb-muted);
	/* Rounded on three sides only. The bar side stays square: a rounded corner meeting one
	   thick border reads as a mistake — but leaving all four square left the cards as the
	   only square thing among rounded chips and buttons, which is what made the widget feel
	   subtly off. */
	border-radius: 0 var(--vxb-radius, 8px) var(--vxb-radius, 8px) 0;
	background: linear-gradient(
		90deg,
		color-mix( in srgb, var(--vxb-ct-cc, transparent) 7%, var(--vxb-bg) ),
		var(--vxb-bg) 55%
	);
	padding: 12px;
	transition: border-color .15s ease, background .15s ease;
}

.vxb-ct-card.dim { opacity: .55; }

/* Only a card with a description expands, so only that card gets an affordance — the row
   already carried `cursor: pointer` and nothing else, which is an interaction with no tell.
   The inline border-left-color wins over this, so the bar keeps the class's colour. */
.vxb-ct-card.clickable .vxb-ct-row { cursor: pointer; }

.vxb-ct-card.clickable:hover {
	border-color: var(--vxb-ct-cc, var(--vxb-border));
	background: linear-gradient(
		90deg,
		color-mix( in srgb, var(--vxb-ct-cc, transparent) 13%, var(--vxb-bg) ),
		var(--vxb-bg) 60%
	);
}

.vxb-ct-row { display: flex; align-items: center; gap: 12px; }

/* min-width:0 lets the name ellipsis instead of forcing the row wider. */
.vxb-classes .vxb-ct-main { flex: 1 1 auto; min-width: 0; }

/* Text colours are forced: the Elementor Kit paints headings and paragraphs globally, and
   a repainted class name on a dark card is unreadable. */
.vxb-classes .vxb-ct-name {
	margin: 0 !important;
	font-size: 0.9375rem !important;
	font-weight: 600;
	line-height: 1.35;
	color: var( --vxb-text ) !important;
	overflow-wrap: anywhere;
}

/* The class's own hours, beside its name — the one question a timetable exists to answer,
   and the end time appears nowhere else on the card. Never breaks mid-range, even though
   the name it sits in wraps anywhere. */
.vxb-classes .vxb-ct-range {
	font-size: 0.85rem !important;
	font-weight: 400;
	color: var( --vxb-muted ) !important;
	white-space: nowrap;
}

.vxb-classes .vxb-ct-meta {
	margin: 3px 0 0 !important;
	font-size: 0.85rem !important;
	line-height: 1.4;
	color: var( --vxb-muted ) !important;
}

.vxb-classes .vxb-ct-side {
	flex: 0 0 auto;
	text-align: right;
	white-space: nowrap;
}

.vxb-classes .vxb-ct-price {
	margin: 0 !important;
	font-size: 0.9375rem !important;
	font-weight: 600;
	line-height: 1.35;
	color: var( --vxb-text ) !important;
}

.vxb-classes .vxb-ct-price.free { color: var( --vxb-completed ) !important; }

.vxb-classes .vxb-ct-seats {
	margin: 3px 0 0 !important;
	font-size: 0.85rem !important;
	line-height: 1.35;
	color: var( --vxb-muted ) !important;
}
.vxb-classes .vxb-ct-seats.is-low { color: var( --vxb-pending ) !important; }

/* "Full" and "Closed" are verdicts, not counts — a badge says so at a glance where dim red
   text was the quietest thing on the card. Still the palette's own status colour. */
.vxb-classes .vxb-ct-seats.is-full,
.vxb-classes .vxb-ct-seats.is-closed {
	display: inline-block;
	margin-top: 4px !important;
	padding: 3px 9px;
	border-radius: 999px;
	background: color-mix( in srgb, var( --vxb-canceled ) 16%, transparent );
	font-weight: 600;
	color: var( --vxb-canceled ) !important;
}

/* The button must size to its label. Left to the theme/Kit it grows to fill the row and
   crushes the class name into a column. */
.vxb-classes .vxb-ct-book {
	flex: 0 0 auto !important;
	width: auto !important;
	min-width: 0 !important;
	height: auto !important;
	min-height: 0 !important;
	align-self: center;
	padding: 9px 18px !important;
	font-size: 0.8125rem !important;
	line-height: 1.3 !important;
	border-radius: var( --vxb-radius, 8px ) !important;
	white-space: nowrap;
	cursor: pointer;
}

.vxb-classes .vxb-ct-book[disabled] {
	opacity: .5;
	cursor: not-allowed;
	pointer-events: none;
}

/* ---------------------------------------------------------------------
 * Inline detail (not a modal — see the template note)
 * ------------------------------------------------------------------- */

.vxb-ct-detail {
	margin-top: 12px;
	padding-top: 12px;
	border-top: 1px solid var(--vxb-border);
}

.vxb-ct-tiles {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
	gap: 8px;
	margin-bottom: 12px;
}

.vxb-ct-tile {
	background: color-mix(in srgb, var(--vxb-text) 6%, transparent);
	border-radius: var(--vxb-radius, 8px);
	padding: 8px 10px;
	min-width: 0;
}

.vxb-ct-tile-k { display: block; font-size: 0.85rem; color: var(--vxb-muted); }
.vxb-ct-tile-v { display: block; font-size: 0.85rem; font-weight: 600; color: var(--vxb-text); }

.vxb-ct-desc {
	margin: 0;
	font-size: 0.8125rem;
	line-height: 1.65;
	color: var(--vxb-muted);
	/* Vendor-authored copy: keep their line breaks, but never let a long word blow out
	   the card on a phone. */
	white-space: pre-line;
	overflow-wrap: break-word;
}

.vxb-ct-msg {
	margin: 10px 0 0;
	font-size: 0.85rem;
	color: var(--vxb-completed);
}

.vxb-ct-msg.bad { color: var(--vxb-canceled); }

/* ---------------------------------------------------------------------
 * Narrow layout
 *
 * @container, NOT @media: this fires on the WIDGET's width, so it works both on a phone and
 * in a narrow Elementor column on a desktop. As a viewport media query it never ran in the
 * second case, and the desktop row simply squeezed — name wrapping mid-word, meta on three
 * lines — which is the state this replaces.
 *
 * The day strip is deliberately untouched: it keeps its full-size chips, its class counts
 * and its horizontal scroll here, exactly as on desktop.
 * ------------------------------------------------------------------- */

@container (max-width: 600px) {
	/* The gutter, rail and dot all go: the card states its own hours now, so a time above it
	   would be the same answer twice on the narrowest screen. */
	.vxb-ct-group {
		grid-template-columns: 1fr;
		gap: 0;
		margin-bottom: 10px;
	}

	.vxb-classes .vxb-ct-time { display: none; }

	/* `display: contents` lifts the name/meta and price/seats out of their wrappers so all
	   six children become cells of one grid — the only way to put the name and price on a
	   shared line while the meta below spans the full width, without rebuilding the DOM. */
	.vxb-ct-row {
		display: grid;
		grid-template-columns: minmax(0, 1fr) auto;
		grid-template-areas:
			"name  price"
			"meta  meta"
			"seats seats"
			"book  book";
		align-items: start;
		gap: 2px 10px;
	}

	.vxb-classes .vxb-ct-main,
	.vxb-classes .vxb-ct-side { display: contents; }

	.vxb-classes .vxb-ct-name { grid-area: name; }
	.vxb-classes .vxb-ct-meta { grid-area: meta; margin-top: 4px !important; }
	.vxb-classes .vxb-ct-price { grid-area: price; text-align: right; }
	.vxb-classes .vxb-ct-seats { grid-area: seats; margin-top: 6px !important; text-align: left; }

	/* The range gets its own line: name + range + price will not share 340px honestly, and a
	   half-wrapped time range reads worse than a second line. */
	.vxb-classes .vxb-ct-range { display: block; }

	/* Full width, because a thumb is not a mouse. */
	.vxb-classes .vxb-ct-book {
		grid-area: book;
		width: 100% !important;
		margin-top: 10px;
		padding: 11px 18px !important;
	}
}

/* Expand affordance on a class card that has details to open. */
.vxb-classes .vxb-ct-chev {
	flex: 0 0 auto;
	/* Fixed slot, ALWAYS present (empty when the class has no detail), so the Book button before
	   it lands at the same edge on every card. */
	width: 22px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	color: var( --vxb-muted ) !important;
	transition: transform 0.15s ease;
}
.vxb-classes .vxb-ct-chev.empty { visibility: hidden; }
.vxb-classes .vxb-ct-chev.open { transform: rotate( 180deg ); }

/* ═══════════════════════════════════════════════════════════════════════════
 * Credit packs — wallet + buy band. Same defensive posture as the rest of this
 * widget: the Elementor Kit repaints headings/paragraphs/buttons globally, so
 * every colour and the Buy button's sizing are forced. Buttons reuse the
 * .ts-btn.ts-btn-2 accent class the trait styles, exactly like .vxb-ct-book.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* Wallet: a compact card stating what the member holds here. */
.vxb-classes .vxb-ct-wallet {
	border: 1px solid var( --vxb-border );
	border-radius: var( --vxb-radius, 12px );
	background: linear-gradient( 90deg, color-mix( in srgb, var(--vxb-accent) 8%, var(--vxb-bg) ), var(--vxb-bg) 70% );
	padding: 12px 14px;
	margin-bottom: 14px;
}
/* The header is the whole collapsed wallet: a button spanning the card. */
.vxb-classes .vxb-ct-wallet-h {
	display: flex; align-items: baseline; gap: 10px;
	width: 100%; background: none; border: 0; padding: 0; margin: 0;
	text-align: left; cursor: pointer; font: inherit;
}
.vxb-classes .vxb-ct-wallet-t {
	flex: 1; font-size: 0.85rem !important; font-weight: 600; letter-spacing: .02em;
	text-transform: uppercase; color: var( --vxb-muted ) !important;
}
.vxb-classes .vxb-ct-wallet-n {
	font-size: 1.125rem !important; font-weight: 700; color: var( --vxb-accent ) !important;
	font-variant-numeric: tabular-nums;
}
/* CSS chevrons, like the agenda's — no icon font dependency. */
.vxb-classes .vxb-ct-wallet-chev,
.vxb-classes .vxb-ct-lot-chev {
	width: 7px; height: 7px; flex: 0 0 auto; align-self: center;
	border-right: 2px solid var( --vxb-muted ); border-bottom: 2px solid var( --vxb-muted );
	transform: rotate( -45deg ); transition: transform .15s ease;
}
.vxb-classes .vxb-ct-wallet.is-open .vxb-ct-wallet-chev,
.vxb-classes .vxb-ct-lot.is-open .vxb-ct-lot-chev { transform: rotate( 45deg ); }

.vxb-classes .vxb-ct-lots { list-style: none; margin: 10px 0 0; padding: 0; }
.vxb-classes .vxb-ct-lot {
	border-top: 1px solid var( --vxb-border );
	font-size: 0.85rem !important; color: var( --vxb-text ) !important;
}
.vxb-classes .vxb-ct-lot-h { display: flex; align-items: center; gap: 8px; }
.vxb-classes .vxb-ct-lot-b {
	flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px;
	background: none; border: 0; padding: 9px 0; margin: 0;
	text-align: left; cursor: pointer; font: inherit; color: inherit;
}
.vxb-classes .vxb-ct-lot-hd { min-width: 0; }
.vxb-classes .vxb-ct-lot-n {
	display: block; font-weight: 600; color: var( --vxb-text ) !important;
	overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.vxb-classes .vxb-ct-lot-sub {
	display: block; font-size: 0.78rem !important; color: var( --vxb-muted ) !important; margin-top: 1px;
}
/* The credits count doubles as the history button — the number raises the question, so it
   answers it. It has to LOOK like a control though: a dotted underline (the "there is more
   behind this" convention, not a link's solid one) plus an info glyph, both firming up on
   hover. Without them it reads as plain text and nobody discovers the history. */
.vxb-classes .vxb-ct-lot-c {
	display: inline-flex; align-items: center; gap: 5px; flex: 0 0 auto;
	background: none; border: 0; padding: 4px 6px; margin: 0; cursor: pointer;
	font: inherit; border-radius: var( --vxb-radius, 8px );
	font-variant-numeric: tabular-nums;
}
.vxb-classes .vxb-ct-lot-cw {
	display: inline-flex; align-items: baseline; gap: 4px;
	border-bottom: 1px dotted var( --vxb-muted );
	padding-bottom: 1px;
}
.vxb-classes .vxb-ct-lot-ci {
	flex: 0 0 auto; color: var( --vxb-muted ); opacity: .75;
	transition: opacity .12s ease, color .12s ease;
}
.vxb-classes .vxb-ct-lot-c:hover { background: var( --vxb-bg-soft ); }
.vxb-classes .vxb-ct-lot-c:hover .vxb-ct-lot-cw { border-bottom-style: solid; border-bottom-color: var( --vxb-accent ); }
.vxb-classes .vxb-ct-lot-c:hover .vxb-ct-lot-ci { color: var( --vxb-accent ); opacity: 1; }
.vxb-classes .vxb-ct-lot-c:hover .vxb-ct-lot-cn { color: var( --vxb-accent ) !important; }
/* Keyboard users get the same promise as the mouse, plus a real focus ring. */
.vxb-classes .vxb-ct-lot-c:focus-visible {
	outline: 2px solid var( --vxb-accent ); outline-offset: 1px; background: var( --vxb-bg-soft );
}
.vxb-classes .vxb-ct-lot-c:focus-visible .vxb-ct-lot-cw { border-bottom-style: solid; border-bottom-color: var( --vxb-accent ); }
.vxb-classes .vxb-ct-lot-c:focus-visible .vxb-ct-lot-ci { color: var( --vxb-accent ); opacity: 1; }
.vxb-classes .vxb-ct-lot-cn { font-weight: 700; color: var( --vxb-text ) !important; }
.vxb-classes .vxb-ct-lot-cx { font-size: 0.78rem !important; color: var( --vxb-muted ) !important; }

.vxb-classes .vxb-ct-lot-d { padding: 0 0 12px 15px; }
.vxb-classes .vxb-ct-lot-r { display: flex; gap: 10px; padding: 2px 0; align-items: baseline; }
.vxb-classes .vxb-ct-lot-k {
	flex: 0 0 92px; font-size: 0.78rem !important; color: var( --vxb-muted ) !important;
}
.vxb-classes .vxb-ct-lot-v { flex: 1; min-width: 0; font-size: 0.82rem !important; }
.vxb-classes .vxb-ct-chip {
	display: inline-block; font-size: 0.78rem !important; margin: 0 4px 4px 0; padding: 2px 9px;
	background: var( --vxb-bg-soft ); border: 1px solid var( --vxb-border ); border-radius: 999px;
}
/* A class the studio has since dropped. It stayed covered by this purchase, so it is
   struck rather than hidden — removing it would rewrite what the member bought. */
.vxb-classes .vxb-ct-chip.is-gone {
	color: var( --vxb-muted ) !important; text-decoration: line-through;
}
.vxb-classes .vxb-ct-lot-gone {
	font-size: 0.76rem !important; color: var( --vxb-muted ) !important; margin: 7px 0 0;
}
.vxb-classes .vxb-ct-lot-chg {
	font-size: 0.78rem !important; line-height: 1.45; margin: 8px 0 0; padding: 7px 10px;
	border-radius: var( --vxb-radius, 8px );
	color: color-mix( in srgb, var( --vxb-pending ) 75%, var( --vxb-text ) ) !important;
	background: color-mix( in srgb, var( --vxb-pending ) 13%, var( --vxb-bg ) );
}

/* Spend history styling lives with the CONFIRM DIALOG rules below — it teleports
   to <body> too, so it cannot be scoped under `.vxb-classes`. */

/* Buy band. */
.vxb-classes .vxb-ct-packs { margin-bottom: 16px; }
.vxb-classes .vxb-ct-packs-h {
	font-size: 0.85rem !important; font-weight: 600; letter-spacing: .02em;
	text-transform: uppercase; color: var( --vxb-muted ) !important; margin-bottom: 8px;
}
.vxb-classes .vxb-ct-pack {
	display: flex; align-items: center; gap: 12px;
	border: 1px solid var( --vxb-border );
	border-left: 3px solid var( --vxb-accent );
	border-radius: 0 var( --vxb-radius, 12px ) var( --vxb-radius, 12px ) 0;
	background: var( --vxb-bg );
	padding: 12px 14px;
}
.vxb-classes .vxb-ct-pack + .vxb-ct-pack { margin-top: 8px; }
.vxb-classes .vxb-ct-pack-main { flex: 1 1 auto; min-width: 0; }
.vxb-classes .vxb-ct-pack-name {
	margin: 0 !important; font-size: 0.9375rem !important; font-weight: 600;
	line-height: 1.35 !important; color: var( --vxb-text ) !important;
}
.vxb-classes .vxb-ct-pack-cr {
	font-size: 0.85rem !important; font-weight: 600; color: var( --vxb-accent ) !important;
	margin-left: 4px;
}
.vxb-classes .vxb-ct-pack-meta {
	margin: 3px 0 0 !important; font-size: 0.85rem !important;
	color: var( --vxb-muted ) !important; line-height: 1.4 !important;
}
.vxb-classes .vxb-ct-pack-side {
	flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: 7px;
}
.vxb-classes .vxb-ct-pack-price {
	font-size: 0.9375rem !important; font-weight: 700; color: var( --vxb-text ) !important;
	font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* Same forced sizing as the Book button, so the Kit can't stretch it. */
.vxb-classes .vxb-ct-buy {
	flex: 0 0 auto !important;
	width: auto !important; min-width: 0 !important;
	height: auto !important; min-height: 0 !important;
	padding: 8px 16px !important;
	font-size: 0.8125rem !important; line-height: 1.3 !important;
	border-radius: var( --vxb-radius, 8px ) !important;
	white-space: nowrap; cursor: pointer;
}
.vxb-classes .vxb-ct-buy:disabled { opacity: .6; cursor: default; }

/* On a phone the pack row stacks so the price + Buy get a full tap target. */
@container (max-width: 600px) {
	.vxb-classes .vxb-ct-pack { flex-direction: column; align-items: stretch; gap: 10px; }
	.vxb-classes .vxb-ct-pack-side { flex-direction: row; align-items: center; justify-content: space-between; }
	.vxb-classes .vxb-ct-buy { width: auto !important; padding: 10px 18px !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
 * Tabbed shell (Schedule / Packs), header balance pill, credit-aware Book, and
 * the pending note. Only rendered where packs are sold, so a plain timetable is
 * byte-for-byte unchanged. Same defensive posture: the Kit repaints headings/
 * buttons globally, so colours + button sizing are forced.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* Header becomes a row so the balance can sit opposite the title. h2's own
   bottom margin is dropped here — the row owns the spacing now. */
.vxb-classes .vxb-ct-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	margin-bottom: 14px;
}
.vxb-classes .vxb-ct-head h2 { margin: 0 !important; }

/* The credit balance: a tappable status pill, not a band. Uses the accent tint
   so it reads as "yours" without a second brand colour. */
.vxb-classes .vxb-ct-balance {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	padding: 5px 12px;
	border-radius: 999px;
	font-size: 0.85rem !important;
	font-weight: 650;
	cursor: pointer;
	white-space: nowrap;
	color: var( --vxb-accent ) !important;
	background: color-mix( in srgb, var(--vxb-accent) 10%, transparent );
	border: 1px solid color-mix( in srgb, var(--vxb-accent) 30%, transparent );
}
.vxb-classes .vxb-ct-balance:hover { background: color-mix( in srgb, var(--vxb-accent) 16%, transparent ); }

/* Segmented Schedule / Packs control. */
.vxb-classes .vxb-ct-tabs {
	display: flex;
	gap: 3px;
	padding: 3px;
	margin-bottom: 14px;
	background: var( --vxb-bg-soft );
	border: 1px solid var( --vxb-border );
	border-radius: 11px;
}
.vxb-classes .vxb-ct-tab {
	flex: 1;
	border: 0 !important;
	background: transparent !important;
	color: var( --vxb-muted ) !important;
	font-weight: 650;
	font-size: 0.875rem !important;
	padding: 8px 6px !important;
	border-radius: 8px !important;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	line-height: 1.2 !important;
}
.vxb-classes .vxb-ct-tab.on {
	background: var( --vxb-accent ) !important;
	color: var( --vxb-on-accent ) !important;
	box-shadow: 0 1px 2px rgba( 0, 0, 0, .14 );
}
.vxb-classes .vxb-ct-tabn {
	font-size: 0.85rem !important;
	font-weight: 700;
	padding: 1px 6px;
	border-radius: 999px;
	background: color-mix( in srgb, var(--vxb-accent) 16%, transparent );
	color: var( --vxb-accent ) !important;
}
/* On the SELECTED (accent) tab the count badge inverts — an accent-tint badge would vanish on
   the accent fill, so it flips to a translucent on-accent chip that reads on the primary colour. */
.vxb-classes .vxb-ct-tab.on .vxb-ct-tabn {
	background: color-mix( in srgb, var( --vxb-on-accent ) 26%, transparent );
	color: var( --vxb-on-accent ) !important;
}

/* Credit-aware Book: the credit button leads, the cash fallback is a quiet link
   beneath it. On desktop-wide cards the container can go inline (see below). */
.vxb-classes .vxb-ct-book-wrap {
	flex: 0 0 auto;
	display: inline-flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 3px;
}
.vxb-classes .vxb-ct-book-alt {
	font-size: 0.85rem !important;
	color: var( --vxb-muted ) !important;
	text-decoration: none !important;
	cursor: pointer;
}
.vxb-classes .vxb-ct-book-alt:hover { color: var( --vxb-text ) !important; text-decoration: underline !important; }

/* Pending purchases note. */
.vxb-classes .vxb-ct-pending {
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 11px 13px;
	margin-bottom: 14px;
	border-radius: 11px;
	background: color-mix( in srgb, var(--vxb-pending) 12%, transparent );
	border: 1px solid color-mix( in srgb, var(--vxb-pending) 30%, transparent );
}
.vxb-classes .vxb-ct-pending-n { font-size: 0.85rem !important; font-weight: 650; color: var( --vxb-text ) !important; }
.vxb-classes .vxb-ct-pending-x { font-size: 0.85rem !important; color: var( --vxb-muted ) !important; }

/* Wide cards: on a roomy container the credit control lays out inline (alt link
   before the button), matching the desktop mockup. Container query, so it also
   fires for a wide widget on desktop, not just a wide viewport. */
/* Desktop alignment: every Book control is one fixed-width column, right-aligned, with the
   "or pay" fallback UNDERNEATH the button (not beside it) so the buttons line up at one edge and
   the eye can scan straight down. The price/seats block gets a min-width so it doesn't jitter.
   Fixed book width + fixed chev slot together anchor the prices to a constant right edge too. */
@container (min-width: 601px) {
	.vxb-classes .vxb-ct-book-wrap {
		flex-direction: column;
		align-items: stretch;
		gap: 3px;
		width: 136px;
		flex: 0 0 auto;
	}
	.vxb-classes .vxb-ct-book-wrap .vxb-ct-book-credit { width: 100% !important; }
	.vxb-classes .vxb-ct-book-wrap .vxb-ct-book-alt { text-align: center; }
	/* The plain Book / Full button matches that column width, so all buttons align. */
	.vxb-classes .vxb-ct-book { width: 136px !important; }
	/* Price + seats: a steady column, right-aligned. */
	.vxb-classes .vxb-ct-side { min-width: 76px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
 * v2 polish: distinct credit colour, capped tabs on desktop, balance dots, the
 * week-range label, and mobile card alignment (the expand chevron + a full-width
 * credit button). Appended last so it wins on source order.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* The credit Book button is honey, not the cash accent — so the two never look alike. */
.vxb-classes .vxb-ct-book.vxb-ct-book-credit {
	background: var( --vxb-credit ) !important;
	border-color: var( --vxb-credit ) !important;
	color: var( --vxb-on-credit ) !important;
}

/* Tabs are full-width on a phone (easy thumb targets) but shouldn't stretch across a wide
   desktop widget — cap and left-align them, as the mockup showed. */
@container (min-width: 601px) {
	.vxb-classes .vxb-ct-tabs { max-width: 320px; }
}

/* Balance pill dots. */
.vxb-classes .vxb-ct-baldots { display: inline-flex; gap: 3px; align-items: center; }
.vxb-classes .vxb-ct-baldot { width: 7px; height: 7px; border-radius: 50%; background: var( --vxb-credit ); }

/* The visible-window range between the arrows. flex:1 so it centres and pushes the arrows
   apart; the Today link follows the forward arrow. */
.vxb-classes .vxb-ct-window {
	flex: 1 1 auto;
	text-align: center;
	font-size: 0.8125rem !important;
	font-weight: 600;
	color: var( --vxb-text ) !important;
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

/* Mobile card: give every element a fixed cell so nothing floats. The expand chevron gets its
   own column beside the price (it was auto-placed before, which is why it wandered), and the
   credit Book control fills the book row full-width just like the plain Book button. */
@container (max-width: 600px) {
	.vxb-ct-row {
		grid-template-columns: minmax(0, 1fr) auto auto;
		grid-template-areas:
			"name  price chev"
			"meta  meta  meta"
			"seats seats seats"
			"book  book  book";
	}
	.vxb-classes .vxb-ct-chev {
		grid-area: chev;
		align-self: start;
		margin-top: 2px;
	}
	/* Both the credit control and the plain button occupy the full book row. */
	.vxb-classes .vxb-ct-book-wrap {
		grid-area: book;
		width: 100%;
		flex-direction: column;
		align-items: stretch;
		margin-top: 10px;
	}
	.vxb-classes .vxb-ct-book-wrap .vxb-ct-book-credit {
		width: 100% !important;
		padding: 11px 18px !important;
	}
	.vxb-classes .vxb-ct-book-wrap .vxb-ct-book-alt {
		text-align: center;
		margin-top: 5px;
	}
}

/* ═══════════════════════════════════════════════════════════════════════════
 * CONFIRM DIALOG. Teleported to <body>, so it is NOT scoped under `.vxb-classes`
 * — every rule roots at `.vxb-ct-modal`, carries its own palette (with light
 * fallbacks, in case the JS couldn't read the widget's), and forces its own
 * look with `!important` so the site's theme / Elementor Kit can't repaint the
 * inputs and buttons the way it does elsewhere.
 * ═══════════════════════════════════════════════════════════════════════════ */

.vxb-ct-modal {
	--vxb-bg: #ffffff;
	--vxb-bg-soft: #f9fafb;
	--vxb-text: #1f2937;
	--vxb-muted: #6b7280;
	--vxb-border: #e5e7eb;
	--vxb-accent: #1f7a54;
	--vxb-on-accent: #ffffff;
	--vxb-credit: #c67c1a;
	--vxb-on-credit: #ffffff;
	--vxb-canceled: #b42318;
	--vxb-radius: 12px;

	position: fixed;
	inset: 0;
	z-index: 100000; /* above Voxel's own popups / sticky headers */
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 20px;
	background: rgba( 17, 24, 39, 0.55 );
	box-sizing: border-box;
	font-size: 0.9375rem;
	line-height: 1.5;
	-webkit-font-smoothing: antialiased;
}
.vxb-ct-modal *,
.vxb-ct-modal *::before,
.vxb-ct-modal *::after { box-sizing: border-box; }

.vxb-ct-dialog {
	width: 100%;
	max-width: 460px;
	max-height: calc( 100vh - 40px );
	overflow-y: auto;
	background: var( --vxb-bg ) !important;
	color: var( --vxb-text ) !important;
	border-radius: calc( var( --vxb-radius ) + 4px );
	box-shadow: 0 18px 50px rgba( 0, 0, 0, 0.28 );
	padding: 22px;
}

.vxb-ct-dialog-h {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 12px;
}
.vxb-ct-dialog-t {
	margin: 0 !important;
	font-size: 1.125rem !important;
	font-weight: 700;
	line-height: 1.3;
	color: var( --vxb-text ) !important;
}
.vxb-ct-dialog-s {
	margin: 4px 0 0 !important;
	font-size: 0.85rem !important;
	color: var( --vxb-muted ) !important;
}
.vxb-ct-dialog-x {
	flex: 0 0 auto;
	width: 32px;
	height: 32px;
	border: 0 !important;
	background: var( --vxb-bg-soft ) !important;
	color: var( --vxb-muted ) !important;
	border-radius: 50%;
	font-size: 20px;
	line-height: 1;
	cursor: pointer;
	display: flex;
	align-items: center;
	justify-content: center;
}
.vxb-ct-dialog-x:hover { color: var( --vxb-text ) !important; }

.vxb-ct-dialog-intro {
	margin: 12px 0 0 !important;
	font-size: 0.875rem !important;
	color: var( --vxb-muted ) !important;
}

.vxb-ct-form {
	margin-top: 16px;
	display: flex;
	flex-direction: column;
	gap: 12px;
}
.vxb-ct-frow {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 12px;
}
.vxb-ct-field {
	display: flex;
	flex-direction: column;
	gap: 5px;
	min-width: 0;
}
.vxb-ct-field-k {
	font-size: 0.8125rem !important;
	font-weight: 600;
	color: var( --vxb-text ) !important;
}
.vxb-ct-field-opt {
	font-weight: 400;
	color: var( --vxb-muted ) !important;
	font-size: 0.75rem !important;
}
.vxb-ct-modal .vxb-ct-input {
	width: 100% !important;
	margin: 0 !important;
	padding: 10px 12px !important;
	font-size: 0.9375rem !important;
	font-family: inherit !important;
	line-height: 1.4 !important;
	color: var( --vxb-text ) !important;
	background: var( --vxb-bg ) !important;
	border: 1px solid var( --vxb-border ) !important;
	border-radius: 10px !important;
	box-shadow: none !important;
	-webkit-appearance: none !important;
	appearance: none !important;
	min-height: 0 !important;
}
.vxb-ct-modal .vxb-ct-input:focus {
	outline: none !important;
	border-color: var( --vxb-accent ) !important;
	box-shadow: 0 0 0 3px color-mix( in srgb, var( --vxb-accent ) 22%, transparent ) !important;
}
.vxb-ct-modal .vxb-ct-input::placeholder { color: var( --vxb-muted ) !important; opacity: 0.8; }
.vxb-ct-modal .vxb-ct-textarea { resize: vertical; min-height: 74px !important; }

.vxb-ct-dialog-msg {
	margin: 0 !important;
	font-size: 0.85rem !important;
}
.vxb-ct-dialog-msg.bad { color: var( --vxb-canceled ) !important; }

.vxb-ct-dialog-f {
	display: flex;
	gap: 10px;
	justify-content: flex-end;
	align-items: center;
	margin-top: 4px;
}
.vxb-ct-modal .vxb-ct-dialog-cancel {
	padding: 10px 16px !important;
	border: 1px solid var( --vxb-border ) !important;
	background: transparent !important;
	color: var( --vxb-text ) !important;
	border-radius: 10px !important;
	font-size: 0.9375rem !important;
	font-family: inherit !important;
	font-weight: 600;
	cursor: pointer;
}
.vxb-ct-modal .vxb-ct-dialog-cancel:hover { background: var( --vxb-bg-soft ) !important; }
.vxb-ct-modal .vxb-ct-dialog-go {
	padding: 10px 20px !important;
	border: 1px solid var( --vxb-accent ) !important;
	background: var( --vxb-accent ) !important;
	color: var( --vxb-on-accent ) !important;
	border-radius: 10px !important;
	font-size: 0.9375rem !important;
	font-family: inherit !important;
	font-weight: 700;
	cursor: pointer;
}
.vxb-ct-modal .vxb-ct-dialog-go.is-credit {
	border-color: var( --vxb-credit ) !important;
	background: var( --vxb-credit ) !important;
	color: var( --vxb-on-credit ) !important;
}
.vxb-ct-modal .vxb-ct-dialog-go[disabled] { opacity: 0.6; cursor: default; }

/* Enter / leave: a quick fade + lift, kept subtle so it never delays the booking. */
.vxb-ct-modal-enter-active,
.vxb-ct-modal-leave-active { transition: opacity 0.18s ease; }
.vxb-ct-modal-enter-from,
.vxb-ct-modal-leave-to { opacity: 0; }
.vxb-ct-modal-enter-active .vxb-ct-dialog,
.vxb-ct-modal-leave-active .vxb-ct-dialog { transition: transform 0.18s ease; }
.vxb-ct-modal-enter-from .vxb-ct-dialog,
.vxb-ct-modal-leave-to .vxb-ct-dialog { transform: translateY( 10px ); }

/* Phone: stack the name/phone-email pairs and let the dialog sit as a bottom sheet, which
   reads as native on mobile and keeps the fields above the keyboard. */
@media (max-width: 560px) {
	.vxb-ct-modal { padding: 0; align-items: flex-end; }
	.vxb-ct-dialog {
		max-width: none;
		border-radius: calc( var( --vxb-radius ) + 6px ) calc( var( --vxb-radius ) + 6px ) 0 0;
		max-height: 92vh;
		padding: 20px 18px calc( 18px + env( safe-area-inset-bottom ) );
	}
	.vxb-ct-frow { grid-template-columns: 1fr; }
	.vxb-ct-dialog-f { flex-direction: column-reverse; align-items: stretch; }
	.vxb-ct-modal .vxb-ct-dialog-cancel,
	.vxb-ct-modal .vxb-ct-dialog-go { width: 100%; text-align: center; }
	.vxb-ct-modal-enter-from .vxb-ct-dialog,
	.vxb-ct-modal-leave-to .vxb-ct-dialog { transform: translateY( 100% ); }
}

/* ═══════════════════════════════════════════════════════════════════════════
 * Packs as an accordion (like the schedule cards): a collapsed row + an
 * expandable detail with description and structured tiles, plus the class-filter
 * fade. Appended last so it overrides the flat-row rules above on source order.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* The pack becomes a column container; the row inside holds the flex layout. */
.vxb-classes .vxb-ct-pack { display: block; }
.vxb-classes .vxb-ct-pack-row { display: flex; align-items: center; gap: 12px; }
.vxb-classes .vxb-ct-pack-main { flex: 1 1 auto; min-width: 0; cursor: pointer; }
.vxb-classes .vxb-ct-pack .vxb-ct-chev { cursor: pointer; }

/* Filtered out: dimmed but still legible, and inert (not clickable or buyable). */
.vxb-classes .vxb-ct-pack.faded { opacity: .4; pointer-events: none; }

/* The packs-tab class filter sits above the list; reuses the schedule filter look. */
.vxb-classes .vxb-ct-pack-filter {
	display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; margin-bottom: 12px;
}

/* Detail, mirroring the schedule card's expand. */
.vxb-classes .vxb-ct-pack-detail {
	margin-top: 12px; padding-top: 12px; border-top: 1px solid var( --vxb-border );
}
.vxb-classes .vxb-ct-pack-desc {
	margin: 0 0 12px !important; font-size: 0.8125rem !important; line-height: 1.65 !important;
	color: var( --vxb-muted ) !important; white-space: pre-line; overflow-wrap: anywhere;
}
.vxb-classes .vxb-ct-pack-tiles {
	display: grid; grid-template-columns: repeat( auto-fit, minmax( 120px, 1fr ) ); gap: 8px;
}
.vxb-classes .vxb-ct-pack-tile {
	background: color-mix( in srgb, var( --vxb-text ) 6%, transparent );
	border-radius: var( --vxb-radius, 8px ); padding: 8px 10px; min-width: 0;
}
.vxb-classes .vxb-ct-pack-tk { display: block; font-size: 0.85rem !important; color: var( --vxb-muted ) !important; }
.vxb-classes .vxb-ct-pack-tv {
	display: block; font-size: 0.85rem !important; font-weight: 600; color: var( --vxb-text ) !important;
	overflow-wrap: anywhere;
}

/* Phone: the ROW stacks (not the whole pack, which now also holds the detail). */
@container (max-width: 600px) {
	.vxb-classes .vxb-ct-pack-row { flex-wrap: wrap; }
	.vxb-classes .vxb-ct-pack-main { flex: 1 1 100%; }
	.vxb-classes .vxb-ct-pack-side {
		flex: 1 1 auto; flex-direction: row; align-items: center; justify-content: space-between;
	}
}

/* ── Spend history ────────────────────────────────────────────────────────────
 * Same modal shell as the confirm dialog (overlay, card, header, close), so only
 * the ledger list needs rules. Rooted at `.vxb-ct-modal` — NOT `.vxb-classes` —
 * because this dialog is teleported to <body> as well. `--vxb-completed` is not
 * part of the palette the dialog carries across, so the credit-returned green is
 * stated literally rather than inherited as a var that would resolve to nothing.
 * ──────────────────────────────────────────────────────────────────────────── */
.vxb-ct-modal .vxb-ct-hist-b { margin-top: 4px; }
.vxb-ct-modal .vxb-ct-hist-msg {
	font-size: 0.85rem !important; color: var( --vxb-muted ) !important; margin: 6px 0;
}
.vxb-ct-modal .vxb-ct-hist-l { list-style: none; margin: 0; padding: 0; }
.vxb-ct-modal .vxb-ct-hist-i {
	display: flex; align-items: baseline; gap: 10px; padding: 8px 0;
	border-bottom: 1px solid var( --vxb-border );
}
.vxb-ct-modal .vxb-ct-hist-i:last-child { border-bottom: 0; }
.vxb-ct-modal .vxb-ct-hist-d {
	flex: 0 0 32px; font-weight: 700; font-size: 0.85rem !important;
	font-variant-numeric: tabular-nums; text-align: right;
}
.vxb-ct-modal .vxb-ct-hist-d.is-in { color: #1f7a54 !important; }
.vxb-ct-modal .vxb-ct-hist-d.is-out { color: var( --vxb-text ) !important; }
.vxb-ct-modal .vxb-ct-hist-w { flex: 1; min-width: 0; }
.vxb-ct-modal .vxb-ct-hist-n {
	display: block; font-size: 0.85rem !important; color: var( --vxb-text ) !important;
}
.vxb-ct-modal .vxb-ct-hist-m {
	display: block; font-size: 0.76rem !important; color: var( --vxb-muted ) !important; margin-top: 1px;
}
/* The ledger can outgrow the viewport on a long-lived pack — scroll the list, not the page. */
.vxb-ct-modal .vxb-ct-hist .vxb-ct-hist-b { max-height: 55vh; overflow-y: auto; }