/* Direction B, "The calendar board", round 3. Slippy Goals' masthead (tone
   ground, pitch band hem, the venue photo hung as a wall calendar page), then
   one white board: the month, the hours with prices, three fact cards and the
   summary panel that never moves. Every choice (day, time, players, how you
   paid, the agree line) is one selector family, defined once below. */
@import url('/assets/brand-page.css?v=fret1');

.xb.page-shell { padding-top: 0; padding-bottom: 0; }
img.x-model-dark { display: none !important; }
[data-theme="dark"] img.x-model-dark { display: block !important; }
[data-theme="dark"] img.x-model-light { display: none !important; }

/* =========================================================================
   The brand's colours (Update 22). The page's main element carries B's tokens
   for light (--xbl-*) and dark (--xbd-*), worked out from the brand's palette
   by public/explore/booking/brand-kit.js with every pairing checked for
   contrast (4.5:1 text, 3:1 rings and edges); this picks the theme's set.
   Without them the brand page's own colours stand in.
   ========================================================================= */
.xb, .x-held-page {
  --xb-tone: var(--xbl-tone, var(--brand-tone));
  --xb-price: var(--xbl-price, var(--brand-accent));
  --xb-text: var(--xbl-text, var(--brand-accent));
  --xb-on: var(--xbl-on, var(--brand-accent));
  --xb-on-ink: var(--xbl-on-ink, var(--brand-accent-ink));
  --xb-on-ink-2: var(--xbl-on-ink-2, var(--brand-accent-ink));
  --xb-ring: var(--xbl-ring, var(--brand-accent));
  --xb-hover-ring: var(--xbl-hover-ring, var(--brand-accent));
  --xb-eye: var(--xbl-eye, var(--ls-ink));
}
[data-theme="dark"] :is(.xb, .x-held-page) {
  --xb-tone: var(--xbd-tone, var(--brand-tone));
  --xb-price: var(--xbd-price, var(--brand-accent));
  --xb-text: var(--xbd-text, var(--brand-accent));
  --xb-on: var(--xbd-on, var(--brand-accent));
  --xb-on-ink: var(--xbd-on-ink, var(--brand-accent-ink));
  --xb-on-ink-2: var(--xbd-on-ink-2, var(--brand-accent-ink));
  --xb-ring: var(--xbd-ring, var(--brand-accent));
  --xb-hover-ring: var(--xbd-hover-ring, var(--brand-accent));
  --xb-eye: var(--xbd-eye, var(--ls-ink));
}

/* =========================================================================
   The selector family. One shape, one ring, one height, one type, five
   states, the brand's accent as the only selected colour.
   ========================================================================= */
.xb, .x-held-page {
  --xs-h: 52px;
  --xs-r: 12px;
  --xs-bg: var(--ls-paper);
  --xs-ink: var(--ls-ink);
  --xs-ink-2: var(--ls-soft);
  --xs-ring: var(--xb-ring);
  --xs-hover-bg: var(--xb-tone);
  --xs-hover-ring: var(--xb-hover-ring);
  --xs-on-bg: var(--xb-on);
  --xs-on-ink: var(--xb-on-ink);
  --xs-on-ink-2: var(--xb-on-ink-2);
  --xs-off-ink: var(--ls-muted);
}
/* the face: every chip draws itself here */
.xb :is(.xb-cell .bkp-day-face, .bkp-time-face, .bkp-seg span, .xs-chip),
.ls .ob-page.x-held-page .paid-option,
.xb .bkp-agree {
  box-sizing: border-box;
  min-height: var(--xs-h);
  border: 0;
  border-radius: var(--xs-r);
  color: var(--xs-ink);
  background: var(--xs-bg);
  box-shadow: inset 0 0 0 1.5px var(--xs-ring);
  font-family: var(--tud-font-secondary);
  font-size: 17px;
  font-weight: 700;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
  transition: background-color 140ms var(--ls-ease, ease), box-shadow 140ms var(--ls-ease, ease), color 140ms var(--ls-ease, ease);
}
/* hover: the brand tone under a full cobalt ring */
.xb.bk-page :is(.bkp-day, .bkp-time, .bkp-seg):hover input:not(:checked) + *,
.xb .xs-chip.is-hover,
.ls .ob-page.x-held-page .paid-option.is-hover,
.ls .ob-page.x-held-page .paid-option:hover:not(:has(input:checked)),
.xb .bkp-agree:hover:not(:has(input:checked)) {
  background: var(--xs-hover-bg);
  box-shadow: inset 0 0 0 2px var(--xs-hover-ring);
}
/* selected: cobalt, white, the second line in the pitch yellow */
.xb.bk-page :is(.bkp-day, .bkp-time, .bkp-seg) input:checked + *,
.xb .xs-chip.is-on,
.ls .ob-page.x-held-page .paid-option:has(input:checked),
.xb .bkp-agree:has(input:checked) {
  color: var(--xs-on-ink);
  background: var(--xs-on-bg);
  box-shadow: inset 0 0 0 2px var(--xs-on-bg);
}
.xb.bk-page :is(.bkp-day, .bkp-time, .bkp-seg) input:checked + * :is(b, span:not(.sr-only)),
.xb .xs-chip.is-on b { color: var(--xs-on-ink); }
.xb.bk-page .xb-times .bkp-time input:checked + * .xb-time-price.x-slot-price,
.xb .xs-chip.is-on .xs-chip-2 { color: var(--xs-on-ink-2); }
/* the site's hover ring belongs to the chip, never to the words inside it */
.xb.bk-page :is(.bkp-day, .bkp-time, .bkp-seg):hover :is(.bkp-day-face, .bkp-time-face) span { box-shadow: none; }
/* focus: the site's ink ring, outside the chip, in every state */
.xb.bk-page :is(.bkp-day, .bkp-time, .bkp-seg) input:focus-visible + *,
.xb .xs-chip.is-focus,
.ls .ob-page.x-held-page .paid-option:has(input:focus-visible),
.xb .bkp-agree:has(input:focus-visible) { outline: 3px solid var(--ls-ink); outline-offset: 2px; }
/* unavailable: no ring, no fill, muted ink; never focusable */
.xb .xb-cell--off,
.xb .xs-chip.is-off { color: var(--xs-off-ink); background: none; box-shadow: none; font-weight: 500; }
/* the radios and the checkbox stay in the tab order, out of sight */
.ls .ob-page.x-held-page .paid-option input,
.xb .bkp-agree input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }

/* =========================================================================
   Masthead: the tone ground, the pitch band hem, the wall calendar page
   ========================================================================= */
.xb-mast { position: relative; overflow: hidden; background: var(--xb-tone); padding-bottom: 18px; }
.xb-mast > .brand-band, .x-held-page .x-mast > .brand-band { position: absolute; left: 0; right: 0; bottom: 0; }
.xb-mast-in { display: grid; grid-template-columns: minmax(0, 1fr) minmax(380px, 460px); column-gap: clamp(32px, 4vw, 72px); align-items: start; padding: 22px 0 58px; }
.xb-title-copy { padding-top: 6px; }
.xb .brand-crumbs { margin: 0 0 14px; }
.xb-title { margin: 0; font-size: clamp(44px, 5.4vw, 76px); font-weight: 800; line-height: .98; letter-spacing: -0.045em; color: var(--ls-ink); }
.xb-lead { margin: 14px 0 0; color: var(--ls-ink-2); font-size: 19px; font-weight: 600; line-height: 1.45; }
.xb-hero-price { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin: 22px 0 0; }
.xb-hero-price strong { color: var(--xb-price); font-family: var(--tud-font-secondary); font-size: 40px; font-weight: 700; line-height: 1; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; }
.xb-hero-price s { color: var(--ls-soft); font-size: 17px; font-weight: 600; }
.xb-facts { display: flex; flex-wrap: wrap; gap: 8px; margin: 20px 0 0; padding: 0; list-style: none; }
.xb-facts li { display: inline-flex; align-items: center; gap: 8px; min-height: 40px; padding: 0 14px 0 10px; border-radius: 999px; background: var(--ls-paper); color: var(--ls-ink); font-size: 15px; font-weight: 700; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--xb-on) 22%, transparent); }
.xb-facts svg { width: 18px; height: 18px; color: var(--xb-text); }
/* The place is a sentence, not a tag: its own full-width line under the pills, the pin beside its first line, so a
   long address wraps as text instead of swelling a pill to two lines. */
.xb-facts .xb-fact--where { flex-basis: 100%; align-items: flex-start; min-height: 0; padding: 6px 0 0; border-radius: 0; background: none; box-shadow: none; font-weight: 600; line-height: 1.45; text-wrap: pretty; }
.xb-facts .xb-fact--where svg { flex: none; margin-top: 2px; }
.xb-facts .xb-fact--where span { max-width: 52ch; }
.xb-doodle { display: block; width: 250px; justify-self: end; }
.xb-doodle img { display: block; width: 100%; height: auto; }

/* the wall calendar page: rings, photo, logo on the edge, a foot line */
.xb-wall { position: relative; justify-self: end; width: 100%; max-width: 460px; margin: 0; padding: 18px 20px 6px 0; pointer-events: none; }
.xb-wall-back { position: absolute; z-index: 0; top: 0; right: 0; width: 58%; height: 78%; overflow: hidden; border: 6px solid var(--ls-paper); border-radius: 18px; background: var(--ls-paper); transform: rotate(5deg); box-shadow: var(--tud-shadow-paper); }
.xb-wall-back img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 62%; }
.xb-wall-sheet { position: relative; z-index: 1; display: block; padding: 12px 12px 0; border-radius: 20px; background: var(--ls-paper); transform: rotate(-2deg); box-shadow: var(--tud-shadow-paper); }
.xb-rings { position: absolute; z-index: 2; top: -15px; left: 0; right: 0; display: flex; justify-content: center; gap: 38%; }
.xb-rings i { display: block; width: 12px; height: 30px; border-radius: 6px; background: var(--ls-ink); box-shadow: 0 0 0 3px var(--ls-paper); }
.xb-wall-photo { display: block; overflow: hidden; border-radius: 12px; aspect-ratio: 16 / 10; background: var(--xb-on); }
.xb-wall-photo img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 45%; }
.xb-wall-foot { display: grid; grid-template-columns: 72px minmax(0, 1fr); column-gap: 14px; align-items: center; padding: 10px 8px 14px; }
.xb-wall-logo { display: block; width: 72px; height: 72px; margin-top: -36px; overflow: hidden; border-radius: 50%; background: #000; box-shadow: 0 0 0 4px var(--ls-paper), 0 0 0 6px var(--xb-on); }
.xb-wall-logo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.xb-wall-name { display: grid; color: var(--ls-ink-2); font-size: 15px; font-weight: 600; line-height: 1.3; }
.xb-wall-name b { color: var(--ls-ink); font-size: 18px; font-weight: 800; letter-spacing: -0.01em; }
.xb-wall-hours { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-top: 12px; padding-top: 12px; border-top: 2px dashed var(--ls-line-2); color: var(--ls-ink-2); font-size: 14px; font-weight: 600; line-height: 1.35; }
.xb-wall-hours b { display: block; color: var(--ls-ink); font-size: 15px; font-weight: 800; }
/* on held and booked the foot carries the booked day */
.xb-wall-date { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 12px; align-items: center; }
.xb-wall-date strong { grid-row: 1 / 3; color: var(--xb-text); font-family: var(--tud-font-secondary); font-size: 52px; font-weight: 700; line-height: .9; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; }
.xb-wall-date b { color: var(--ls-ink); font-size: 18px; font-weight: 800; line-height: 1.2; }
.xb-wall-date span { color: var(--ls-ink-2); font-size: 15px; font-weight: 600; }

/* =========================================================================
   The board
   ========================================================================= */
.xb-band { position: relative; padding: clamp(40px, 5vw, 64px) 0 clamp(48px, 5vw, 72px); background: var(--ls-paper); }
.xb-board { display: grid; grid-template-columns: minmax(0, 1fr) 360px; grid-template-areas: "steps side" "work side" "info side"; grid-template-rows: auto auto 1fr; column-gap: clamp(28px, 3.5vw, 56px); align-items: start; border: 0; border-radius: 0; background: none; }
.xb-steps { grid-area: steps; padding: 0 0 22px; }
.xb-board > .bkp-step { grid-area: work; padding: 0; }
.xb-pick { display: grid !important; grid-template-columns: 372px minmax(0, 1fr); column-gap: 28px; align-items: start; }
.xb-pick[hidden] { display: none !important; }
.xb .bkp-label { font-size: 15px; font-weight: 800; }
.xb-cal > .bkp-label, .xb-slots > .bkp-label { margin-bottom: 10px; }

/* the month: open days are chips, closed days sit flat */
.xb-cal-box { padding: 10px 12px 14px; border-radius: 18px; box-shadow: inset 0 0 0 1.5px var(--ls-line-2); }
.xb-month-head { display: grid; grid-template-columns: 44px 1fr 44px; align-items: center; margin: 0 -4px 2px; }
.xb-month-name { margin: 0; text-align: center; font-size: 17px; font-weight: 800; }
.xb-arrow { display: grid; place-items: center; width: 44px; height: 44px; border: 0; border-radius: var(--xs-r); background: none; color: var(--ls-ink); cursor: pointer; }
.xb-arrow:hover:not(:disabled) { background: var(--xs-hover-bg); box-shadow: inset 0 0 0 2px var(--xs-hover-ring); }
.xb-arrow:disabled { color: var(--ls-line-2); cursor: default; }
.xb-arrow:focus-visible { outline: 3px solid var(--ls-ink); outline-offset: 2px; }
.xb-week { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; }
.xb-week span { padding: 6px 0; color: var(--ls-soft); font-size: 13px; font-weight: 700; text-align: center; }
.xb-grid { display: grid; gap: 4px; }
.xb-row { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; }
.xb-cell { display: grid; place-items: center; height: var(--xs-h); font-family: var(--tud-font-secondary); font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; }
.xb .xb-cell .bkp-day-face { display: grid; place-items: center; width: 100%; height: 100%; padding: 0; }

/* the hours, each with its price */
.xb-slots { min-width: 0; }
.xb-times-day { grid-column: 1 / -1; margin: 0 0 6px; font-size: 22px; font-weight: 800; letter-spacing: -0.02em; }
.xb .xb-times .bkp-time-face { display: flex; justify-content: space-between; align-items: center; gap: 10px; padding: 0 16px; }
.xb-time-when { color: var(--xs-ink-2); font-family: var(--tud-font-primary); font-size: 15px; font-weight: 600; white-space: nowrap; }
.xb-time-when b { color: var(--xs-ink); font-family: var(--tud-font-secondary); font-size: 17px; font-weight: 700; }
.xb-time-to { color: var(--xs-ink-2); }
.xb .xb-time-price { color: var(--xs-ink-2); font-family: var(--tud-font-secondary); font-size: 15px; font-weight: 700; }
.xb .bkp-time.is-taken .bkp-time-face { text-decoration: none; }

/* players: the same chip, three across */
.xb .xb-segs { gap: 8px; }
.xb .bkp-seg span { display: grid; place-items: center; }

/* the summary panel that never moves */
.xb-side { grid-area: side; position: sticky; top: 96px; z-index: 2; border: 1px solid var(--ls-line); border-radius: 22px; background: var(--ls-canvas); }
/* the panel does not clip, so the turning page can break out above its top edge mid-turn (Update 18); the head and
   the last part round their own corners instead. z-index 2 keeps it over the board and under the sticky header. */
.xb-side > :first-child { border-radius: 21px 21px 0 0; }
.xb-side > :last-child { border-radius: 0 0 21px 21px; }
.xb-side-head { display: grid; justify-items: center; gap: 6px; padding: 44px 24px 18px; background: var(--xb-tone); }
.xb-side > .brand-band { height: 12px; }
.xb-side-body { display: grid; gap: 18px; padding: 20px 24px 24px; }
.xb-model { display: block; width: 120px; margin: -6px auto 6px; }
.xb-model img { display: block; width: 100%; height: auto; }
.x-model-dark { display: none; }
.xb-price { text-align: center; }
.xb-price-now { display: flex; justify-content: center; align-items: baseline; gap: 10px; margin: 0; }
/* the price never breaks */
.xb-price-now strong, .xb-hero-price strong { white-space: nowrap; }
.xb-price-now strong { font-family: var(--tud-font-secondary); font-size: 36px; font-weight: 700; line-height: 1; letter-spacing: -0.04em; }
.xb-price-now s { color: var(--ls-soft); font-size: 16px; font-weight: 600; }
.xb-price-for { margin: 6px 0 0; color: var(--ls-ink-2); font-size: 15px; font-weight: 700; }
.xb .xb-summary { position: static !important; margin: 0; padding: 16px 0 0 !important; border-radius: 0; background: none; box-shadow: none !important; border-top: 2px dashed var(--ls-line-2); }
.xb .xb-summary::before { display: none; }

/* under the picker: the facts as three equal cards, then who you pay */
.xb-info { grid-area: info; margin-top: 44px; min-width: 0; }
.xb-cards { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.5fr); gap: 12px; }
.xb-board:has(> [data-step="details"]:not([hidden])) .xb-card--cancel { display: none; }
.xb-board:has(> [data-step="details"]:not([hidden])) .xb-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.xb-card { display: grid; align-content: start; gap: 8px; padding: 20px 20px 22px; border-radius: 18px; background: var(--ls-canvas); box-shadow: inset 0 0 0 1px var(--ls-line); }
.xb-card-icon { display: grid; place-items: center; width: 44px; height: 44px; margin-bottom: 4px; border-radius: 12px; color: var(--xb-price); background: var(--xb-tone); }
.xb-h { margin: 0; font-size: 17px; font-weight: 800; letter-spacing: -0.01em; }
.xb-card p { margin: 0; color: var(--ls-ink-2); font-size: 15px; line-height: 1.5; }
.xb-lines { display: grid; gap: 4px; margin: 0; padding-left: 1.1em; color: var(--ls-ink-2); font-size: 15px; line-height: 1.45; }
.xb-paid { display: grid; grid-template-columns: 112px minmax(0, 1fr); align-items: center; gap: 24px; margin-top: 12px; padding: 16px 28px 16px 24px; border-radius: 18px; background: var(--xb-tone); }
.xb-paid-art { display: block; width: 112px; }
.xb-paid-art img { display: block; width: 100%; height: auto; mix-blend-mode: multiply; }
.xb-paid .slip-pay { display: flex; gap: 10px; align-items: flex-start; margin: 0; color: var(--ls-ink-2); font-size: 16px; line-height: 1.45; }
.xb-paid .slip-pay b { color: var(--ls-ink); }

/* the details step */
.xb-board > [data-step="details"] { gap: 18px; }
.xb-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.xb-fields > :first-child { grid-column: 1 / -1; }
.xb .bkp-private { margin: 0; color: var(--ls-ink-2); font-size: 15px; }
.xb .bkp-policy { padding: 18px 20px; border-radius: 16px; background: var(--ls-canvas); box-shadow: inset 0 0 0 1px var(--ls-line); }
.xb .bkp-policy .bkp-label { margin-bottom: 8px; }
/* the agree line is a chip: a box that fills with the pitch yellow */
.xb .bkp-agree { position: relative; display: flex; align-items: center; gap: 12px; padding: 12px 18px 12px 16px; font-family: var(--tud-font-primary); font-size: 16px; cursor: pointer; }
.xb .bkp-agree > span { position: relative; display: block; padding-left: 36px; }
.xb .bkp-agree > span::before { content: ""; position: absolute; left: 0; top: 50%; width: 22px; height: 22px; margin-top: -11px; border-radius: 6px; box-shadow: inset 0 0 0 2px currentColor; }
.xb .bkp-agree:has(input:checked) > span::before { background: var(--xs-on-ink-2); box-shadow: none; }
.xb .bkp-agree:has(input:checked) > span::after { content: ""; position: absolute; left: 8px; top: 50%; width: 6px; height: 12px; margin-top: -8px; border: solid var(--xs-on-bg); border-width: 0 2.5px 2.5px 0; transform: rotate(45deg); }
.xb .bkp-agree + .field-error { margin-top: -8px; }
.xb .bkp-back { justify-self: start; }

/* =========================================================================
   Held and booked on /bookings/: the same masthead, then the page beside a
   side panel that carries the ticket, like the board's summary
   ========================================================================= */
.x-held-page .theme-art.ob-side { display: none !important; }
.x-held-page .x-mast { position: relative; overflow: hidden; background: var(--xb-tone); padding-bottom: 18px; }
.x-held-page .x-mast-in { display: grid; grid-template-columns: minmax(0, 1fr) minmax(380px, 460px); column-gap: clamp(32px, 4vw, 72px); align-items: center; padding: 20px 0 58px; }
.x-held-page .x-mast-copy { min-width: 0; }
.x-held-page .x-mast-copy .order-back { margin-bottom: 18px; }
.x-held-page .x-brandrow { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin: 0 0 16px; font-size: 17px; font-weight: 800; }
.x-held-page .x-brandlogo { display: inline-block; flex: none; width: 48px; height: 48px; overflow: hidden; border-radius: 50%; background: #000; box-shadow: 0 0 0 2px var(--ls-paper), 0 0 0 3.5px var(--xb-on); }
.x-held-page .x-brandlogo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.x-held-page .x-state { margin: 0; font-size: clamp(48px, 6vw, 84px); font-weight: 800; line-height: .96; letter-spacing: -0.05em; }
.x-held-page .x-lead { margin: 16px 0 0; color: var(--ls-ink); font-size: 20px; font-weight: 700; line-height: 1.35; }
.x-held-page .order-code { margin: 10px 0 0; color: var(--ls-ink-2); }
.x-held-page .x-mast-art { min-width: 0; }
.x-held-page .x-mast-art .xb-wall { justify-self: stretch; margin-left: auto; }

.ls .ob-page.x-held-page .bk-detail { display: grid !important; grid-template-columns: minmax(0, 1fr) 400px; column-gap: clamp(28px, 3.5vw, 56px); align-items: start; margin-top: 48px; }
.x-held-page .bk-detail .ob-main { grid-column: 1; grid-row: 1; max-width: none; }
.x-held-page:is(.x-state-held, .x-state-sent) .bk-detail .ob-main > aside.slip { display: none; }
.xb-tside { grid-column: 2; grid-row: 1; position: sticky; top: 96px; overflow: clip; border: 1px solid var(--ls-line-2); border-radius: 22px; background: var(--ls-paper); box-shadow: var(--tud-shadow-card-raised); }
.xb-tside-head { display: grid; place-items: center; padding: 20px 24px 14px; background: var(--xb-tone); }
.xb-tside-head .x-model { display: block; width: 150px; }
.xb-tside-head img { display: block; width: 100%; height: auto; }
.xb-tside > .brand-band { height: 12px; }
.x-held-page .xb-tside .x-ticket { margin: 0; border-radius: 0; background: none; box-shadow: none; }
.x-held-page .x-ticket-top { padding: 20px 24px 16px; }
.x-held-page .x-ticket-title { margin: 0 0 6px; font-size: 20px; font-weight: 800; letter-spacing: -0.02em; }
.x-held-page .x-ticket .slip-rows { margin: 0; }
.x-held-page .x-ticket-stub { padding: 18px 24px 22px; border-top: 2px dashed var(--ls-line-2); background: var(--ls-canvas); }
.x-held-page .x-ticket-stub .pay-slip { margin: 0; padding: 0; border: 0; background: none; }
.x-held-page .x-ticket-stub .pay-slip::before, .x-held-page .x-ticket-stub .pay-slip::after { display: none; }
.x-held-page .x-ticket .bk-voucher { margin: 0; padding: 22px 24px 24px; border-radius: 0; box-shadow: none; }
.x-held-page .bk-voucher dt { white-space: nowrap; padding-right: 12px; }
.x-held-page .bk-qr svg { display: block; width: 100%; height: auto; }
.x-held-page .pay-panel { border-width: 1.5px; }
.x-held-page .pay-panel .pay-title { font-size: 24px; }
.ls .ob-page.x-held-page .paid-options { display: flex; flex-wrap: wrap; gap: 8px; }
.ls .ob-page.x-held-page .paid-option { position: relative; display: inline-flex; align-items: center; justify-content: center; min-width: 140px; padding: 0 20px; font-family: var(--tud-font-primary); font-size: 16px; white-space: nowrap; cursor: pointer; }
.ls .ob-page.x-held-page .paid-option > span { color: inherit; }

/* =========================================================================
   iPad and small laptops
   ========================================================================= */
@media (min-width: 900px) and (max-width: 1180px) {
  .xb-mast-in, .x-held-page .x-mast-in { grid-template-columns: minmax(0, 1fr) minmax(320px, 400px); column-gap: 32px; }
  .xb-board { grid-template-columns: minmax(0, 1fr) 312px; column-gap: 28px; }
  .xb-pick { grid-template-columns: minmax(292px, 340px) minmax(0, 1fr); column-gap: 20px; }
  .xb-time-to { display: none; }
  .xb-side-head, .xb-side-body { padding-left: 20px; padding-right: 20px; }
  .ls .ob-page.x-held-page .bk-detail { grid-template-columns: minmax(0, 1fr) 340px; column-gap: 28px; }
}

/* =========================================================================
   Phones: art first, then the title and lead, then the board; the summary
   panel closes the board as its last card, its button full width
   ========================================================================= */
@media (max-width: 899px) {
  .xb-mast-in { grid-template-columns: minmax(0, 1fr); padding: 0 0 40px; }
  .xb-title-copy { display: contents; }
  .xb .brand-crumbs { order: 0; margin: 16px 0 6px; }
  .xb-wall, .xb-doodle { order: 1; }
  .xb-title { order: 2; margin-top: 20px; font-size: clamp(40px, 11vw, 52px); }
  .xb-lead { order: 3; font-size: 17px; }
  .xb-hero-price { order: 4; margin-top: 18px; }
  .xb-hero-price strong { font-size: 34px; }
  .xb-facts { order: 5; margin-top: 16px; }
  .xb-wall { justify-self: stretch; max-width: none; padding: 18px 12px 4px 4px; }
  .xb-wall-back { width: 54%; height: 70%; right: 2px; transform: rotate(4deg); }
  .xb-wall-sheet { transform: rotate(-1.5deg); }
  .xb-wall-foot { grid-template-columns: 60px minmax(0, 1fr); column-gap: 12px; padding: 8px 4px 12px; }
  .xb-wall-logo { width: 60px; height: 60px; margin-top: -30px; }
  .xb-wall-hours { gap: 10px; font-size: 13px; }
  .xb-wall-hours b { font-size: 14px; }
  .xb-doodle { width: min(56%, 200px); justify-self: center; margin: 8px 0 0; }

  .xb-band { padding: 28px 0 56px; }
  .xb-board { grid-template-columns: minmax(0, 1fr); grid-template-areas: "steps" "work" "side" "info"; grid-template-rows: none; }
  .xb-pick { grid-template-columns: minmax(0, 1fr); row-gap: 24px; }
  /* the month, phone first: only the weeks that have open days, edge to edge */
  .xb-row--quiet { display: none; }
  .xb-cal-box { padding: 0; box-shadow: none; }
  .xb-week, .xb-row { gap: 2px; }
  .xb-grid { gap: 4px; }
  .xb-week span { padding: 2px 0 6px; font-size: 12px; }
  .xb-month-head { margin: 0 -10px 4px; }
  /* the hours two by two, the price beside each */
  .xb-times-day { font-size: 19px; }
  .xb-time-to { display: none; }
  .xb .xb-times .bkp-time-face { gap: 6px; padding: 0 12px; }
  /* the panel: the model and the price side by side, then players and the button */
  .xb-side { position: relative; top: auto; margin-top: 32px; }
  /* the model sits 6px in from the head's edge so the turning page clears the panel's side */
  .xb-side-head { grid-template-columns: 102px minmax(0, 1fr); justify-items: start; align-items: center; column-gap: 10px; padding: 30px 20px 16px; }
  .xb-model { width: 96px; margin: 0 0 0 6px; }
  .xb-price, .xb-price-now { text-align: left; justify-content: flex-start; }
  .xb-price-now strong { font-size: 32px; }
  .xb-side-body { padding: 18px 20px 22px; }
  .xb-info { margin-top: 32px; }
  .xb-cards, .xb-board:has(> [data-step="details"]:not([hidden])) .xb-cards { grid-template-columns: minmax(0, 1fr); }
  .xb-card { grid-template-columns: 44px minmax(0, 1fr); column-gap: 14px; align-items: start; padding: 18px; }
  .xb-card-icon { grid-row: 1 / 3; margin: 0; }
  .xb-paid { grid-template-columns: 84px minmax(0, 1fr); gap: 16px; padding: 16px 18px 16px 16px; }
  .xb-paid-art { width: 84px; }
  .xb-paid .slip-pay { font-size: 15px; }
  .xb-fields { grid-template-columns: minmax(0, 1fr); }

  .x-held-page .x-mast-in { grid-template-columns: minmax(0, 1fr); padding: 0 0 40px; }
  .x-held-page .x-mast-copy { display: contents; }
  .x-held-page .order-back { order: 0; justify-self: start; margin: 12px 0 0 !important; }
  .x-held-page .x-mast-art { order: 1; }
  .x-held-page .x-brandrow { order: 2; margin: 20px 0 14px; }
  .x-held-page .x-state { order: 3; font-size: clamp(44px, 12vw, 56px); }
  .x-held-page .x-lead { order: 4; font-size: 18px; }
  .x-held-page .order-code { order: 5; }
  .ls .ob-page.x-held-page .bk-detail { grid-template-columns: minmax(0, 1fr); row-gap: 24px; margin-top: 28px; }
  .x-held-page .bk-detail .ob-main { grid-row: 2; }
  .xb-tside { grid-column: 1; grid-row: 1; position: static; }
  .xb-tside-head .x-model { width: 128px; }
  .ls .ob-page.x-held-page .paid-option { flex: 1 1 0; min-width: 0; padding: 0 12px; }
}
@media (max-width: 370px) {
  .xb-side-head { grid-template-columns: 82px minmax(0, 1fr); column-gap: 6px; }
  .xb-model { width: 76px; }
  .xb-price-now { flex-wrap: wrap; gap: 2px 8px; }
  .xb-price-now strong { font-size: 28px; }
  .xb .xb-times .bkp-time-face { padding: 0 10px; }
  .xb-time-when b { font-size: 16px; }
  .xb .xb-time-price { font-size: 14px; }
  .xb-wall-hours { grid-template-columns: minmax(0, 1fr); gap: 6px; }
}

/* dark follows light: the picked chip keeps one ink on the pale dark accent */
[data-theme="dark"] .xb-paid-art img { mix-blend-mode: normal; }
.xb-side:has(.x-none) .xb-side-body { display: none; }
/* the booked ticket is taller than a screen: it scrolls with the page */
.x-held-page.x-state-booked .xb-tside { position: static; }

/* =========================================================================
   Beside the month, the hours scroll in a box that ends where the month
   ends: a soft fade marks hours hidden above or below, the page is never
   pulled along. With a mouse the bar has its own gutter, 10 px clear of the
   rows, so it never covers a row, its border, its focus ring or its fill;
   it shows only when the list overflows, slim and pale at rest, full cobalt
   and a touch wider on hover and while dragged. Touch keeps the platform's
   own indicator. Where the hours stack under the month (phones, and 900 to
   999 px), every hour shows in the two-across grid, with no inner scroll.
   ========================================================================= */
.xb-pick { align-items: stretch; }
.xb-cal { align-self: start; }
.xb-slots { display: flex; flex-direction: column; min-height: 0; }
.xb .xb-times { display: flex; flex: 1 1 auto; flex-direction: column; min-height: 0; }
.xb .xb-times[hidden] { display: none; }
.xb-times-scroll { position: relative; flex: 1 1 auto; min-height: 180px; }
.xb-times-list {
  position: absolute; inset: -6px -6px 0 -6px;
  display: grid; grid-template-columns: minmax(0, 1fr); align-content: start; gap: 8px;
  padding: 6px;
  overflow-y: auto; overscroll-behavior: contain;
}
.xb-times-list .bkp-time { scroll-margin-block: 36px; }
.xb-times-scroll::before, .xb-times-scroll::after {
  content: ""; position: absolute; z-index: 1; left: -6px; right: 0; height: 40px;
  pointer-events: none; opacity: 0; transition: opacity .18s ease;
}
.xb-times-scroll::before { top: -6px; background: linear-gradient(var(--ls-paper) 15%, color-mix(in srgb, var(--ls-paper) 0%, transparent)); }
.xb-times-scroll::after { bottom: 0; background: linear-gradient(color-mix(in srgb, var(--ls-paper) 0%, transparent), var(--ls-paper) 85%); }
.xb-times-scroll.is-more-above::before, .xb-times-scroll.is-more-below::after { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .xb-times-scroll::before, .xb-times-scroll::after { transition: none; } }

/* a mouse: the bar in its own gutter, the rows the same width with or without it */
@media (hover: hover) and (pointer: fine) and (min-width: 1000px) {
  .xb-times-list { inset: -6px -20px 0 -6px; padding: 6px 10px 6px 6px; overflow-y: scroll; scrollbar-gutter: stable; }
  .xb-times-list::-webkit-scrollbar { width: 10px; }
  .xb-times-list::-webkit-scrollbar-track { border-radius: 10px; background: transparent; }
  .xb-times-scroll.is-overflow .xb-times-list::-webkit-scrollbar-track { background: color-mix(in srgb, var(--xs-on-bg) 7%, transparent); }
  .xb-times-list::-webkit-scrollbar-thumb { border: 2px solid transparent; border-radius: 10px; background: color-mix(in srgb, var(--xs-on-bg) 40%, var(--ls-paper)) padding-box; }
  .xb-times-list:hover::-webkit-scrollbar-thumb, .xb-times-list.is-hover::-webkit-scrollbar-thumb { border-width: 1px; background-color: var(--xs-on-bg); }
  .xb-times-list::-webkit-scrollbar-thumb:active { border-width: 1px; background-color: var(--xs-on-bg); }
  /* Firefox draws the standard bar (a browser that styles ::-webkit-scrollbar ignores it if these are set) */
  @supports not selector(::-webkit-scrollbar) {
    .xb-times-list { inset: -6px -18px 0 -6px; scrollbar-width: thin; scrollbar-color: transparent transparent; }
    .xb-times-scroll.is-overflow .xb-times-list { scrollbar-color: color-mix(in srgb, var(--xs-on-bg) 40%, var(--ls-paper)) color-mix(in srgb, var(--xs-on-bg) 7%, transparent); }
    .xb-times-scroll.is-overflow .xb-times-list:is(:hover, .is-hover) { scrollbar-color: var(--xs-on-bg) color-mix(in srgb, var(--xs-on-bg) 7%, transparent); }
  }
}

/* stacked under the month: the full two-across grid, as before the scroll */
@media (max-width: 999px) {
  .xb-pick { align-items: start; }
  .xb .xb-times { flex: none; }
  .xb-times-scroll { flex: none; min-height: 0; }
  .xb-times-list { position: static; inset: auto; margin: 0; padding: 0; overflow: visible; max-height: none; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .xb-times-scroll::before, .xb-times-scroll::after { display: none; }
}
/* narrow tablets: no room for the hours beside the month, so they sit under it */
@media (min-width: 900px) and (max-width: 999px) {
  .xb-pick { grid-template-columns: minmax(0, 1fr); row-gap: 24px; }
  .xb-cal { max-width: 440px; }
}

/* =========================================================================
   Messages with Slippy Goals: a thread. Status updates are quiet centred
   lines (the newest on a soft yellow pill), a divider where the day changes,
   Slippy Goals on the left beside its logo, the student on the right in
   cobalt. The thread scrolls in the card and opens at the newest item; one
   rounded composer closes the card.
   ========================================================================= */
.ls .x-held-page .xm-card .bk-thread {
  display: flex; flex-direction: column; gap: 10px;
  max-height: 440px; margin: 4px -8px 0; padding: 4px 8px 12px;
  overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: var(--xs-ring) transparent;
}
.ls .x-held-page .xm-card .xm-day { display: flex; align-items: center; gap: 12px; margin: 6px 0 2px; color: var(--ls-soft); font-size: 13px; font-weight: 700; }
.ls .x-held-page .xm-card .xm-day::before, .ls .x-held-page .xm-card .xm-day::after { content: ""; flex: 1; height: 1px; background: var(--ls-line-2); }

/* status lines: one small component. An icon disc, then the title with its
   time at the right edge, the detail under the title on the same left edge.
   Older ones are quiet, the newest sits on a soft cobalt tint with a
   hairline and its disc in the status colour. */
.ls .x-held-page .xm-card .bk-event.xm-ev {
  display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; grid-template-areas: "icon title time" "icon detail detail";
  column-gap: 10px; row-gap: 1px; align-items: baseline; align-self: center;
  width: fit-content; max-width: min(100%, 440px); margin: 2px 0; padding: 9px 14px 10px 10px;
  border: 1px solid transparent; border-radius: 14px; background: none; box-shadow: none;
  color: var(--ls-ink-2); font-size: 14px; line-height: 1.4; text-align: left;
}
.ls .x-held-page .xm-card .xm-ev--one { grid-template-areas: "icon title time"; }
.ls .x-held-page .xm-card .xm-ev .xm-ev-icon {
  grid-area: icon; align-self: center; display: grid; place-items: center; width: 28px; height: 28px; margin-top: 1px;
  border-radius: 50%; color: var(--ls-ink-2); background: none; box-shadow: inset 0 0 0 1px var(--ls-line-2);
}
.ls .x-held-page .xm-card .xm-ev .xm-ev-icon svg { width: 15px; height: 15px; }
.ls .x-held-page .xm-card .xm-ev .xm-ev-title { grid-area: title; min-width: 0; color: var(--ls-ink); font-size: 14px; font-weight: 700; }
.ls .x-held-page .xm-card .xm-ev .xm-ev-detail { grid-area: detail; min-width: 0; color: var(--ls-ink-2); }
.ls .x-held-page .xm-card .xm-ev .xm-time { grid-area: time; justify-self: end; margin: 0; padding-left: 12px; color: var(--ls-soft); font-family: var(--tud-font-secondary); font-size: 12px; font-weight: 500; white-space: nowrap; }
.ls .x-held-page .xm-card .xm-ev .xm-time::before { content: none; }
/* the newest: clearly current, calm */
.ls .x-held-page .xm-card .xm-ev.is-latest {
  border-color: color-mix(in srgb, var(--xs-on-bg) 24%, var(--ls-paper));
  background: color-mix(in srgb, var(--xs-on-bg) 6%, var(--ls-paper));
}
.ls .x-held-page .xm-card .xm-ev.is-latest .xm-ev-icon { color: var(--xs-on-bg); box-shadow: inset 0 0 0 1.5px var(--xs-on-bg); }
.ls .x-held-page .xm-card .xm-ev.is-latest.xm-ev--confirmed .xm-ev-icon,
.ls .x-held-page .xm-card .xm-ev.is-latest.xm-ev--booked .xm-ev-icon { color: var(--xs-on-ink); background: var(--xs-on-bg); box-shadow: none; }
.ls .x-held-page .xm-card .xm-ev.is-latest.xm-ev--ended { border-color: var(--ls-line-2); background: var(--ls-canvas); }
.ls .x-held-page .xm-card .xm-ev.is-latest.xm-ev--ended .xm-ev-icon { color: var(--ls-ink); box-shadow: inset 0 0 0 1.5px var(--ls-ink-2); }
/* an older confirmation keeps its filled disc, in a quiet tone */
.ls .x-held-page .xm-card .xm-ev:not(.is-latest).xm-ev--confirmed .xm-ev-icon { color: var(--ls-paper); background: var(--ls-ink-2); box-shadow: none; }

/* messages */
.ls .x-held-page .xm-card .bk-msg {
  display: grid; grid-template-columns: 32px minmax(0, auto); grid-template-areas: "disc bubble" ". time"; column-gap: 8px; row-gap: 4px;
  align-self: flex-start; justify-items: start; max-width: min(84%, 460px);
  margin: 0; padding: 0; border-radius: 0; background: none; box-shadow: none; white-space: normal;
}
.ls .x-held-page .xm-card .bk-msg--mine { grid-template-columns: minmax(0, auto); grid-template-areas: "bubble" "time"; align-self: flex-end; justify-items: end; }
.ls .x-held-page .xm-card .xm-disc { grid-area: disc; align-self: end; width: 32px; height: 32px; overflow: hidden; border-radius: 50%; background: #000; box-shadow: 0 0 0 2px var(--ls-paper), 0 0 0 3px var(--xb-on); margin-bottom: 2px; }
.ls .x-held-page .xm-card .xm-disc img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ls .x-held-page .xm-card .xm-bubble {
  grid-area: bubble; display: grid; gap: 8px; justify-items: start;
  padding: 10px 14px; border-radius: 18px 18px 18px 6px;
  color: var(--ls-ink); background: var(--ls-canvas); box-shadow: inset 0 0 0 1px var(--ls-line-2);
  font-size: 16px; line-height: 1.4; white-space: pre-line; overflow-wrap: anywhere;
}
.ls .x-held-page .xm-card .bk-msg--mine .xm-bubble { border-radius: 18px 18px 6px 18px; color: var(--xs-on-ink); background: var(--xs-on-bg); box-shadow: none; justify-items: end; }
.ls .x-held-page .xm-card .bk-msg .xm-time { grid-area: time; padding: 0 6px; color: var(--ls-soft); font-family: var(--tud-font-secondary); font-size: 12px; font-weight: 500; }
.ls .x-held-page .xm-card .bk-seen { align-self: flex-end; margin-top: -6px; padding: 0 6px; color: var(--ls-soft); font-size: 12px; }

/* an attachment, a compact chip inside its bubble */
.ls .x-held-page .xm-card .xm-file {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px; margin: 0; padding: 0 14px 0 10px;
  border: 0; border-radius: 12px; color: var(--ls-ink); background: var(--ls-paper); box-shadow: inset 0 0 0 1px var(--ls-line-2);
  font: 700 14px/1.2 var(--tud-font-primary); text-decoration: none; cursor: pointer;
}
.ls .x-held-page .xm-card .bk-msg--mine .xm-file { color: var(--xs-on-ink); background: color-mix(in srgb, var(--xs-on-ink) 14%, transparent); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--xs-on-ink) 30%, transparent); }
.ls .x-held-page .xm-card .xm-file:hover { background: var(--xs-hover-bg); color: var(--ls-ink); }
.ls .x-held-page .xm-card .xm-file:focus-visible { outline: 3px solid var(--ls-ink); outline-offset: 2px; }

/* nothing said yet */
.ls .x-held-page .xm-card .xm-empty { display: grid; justify-items: center; gap: 4px; margin: 8px 0; padding: 22px 16px; border-radius: 16px; background: var(--ls-canvas); box-shadow: inset 0 0 0 1px var(--ls-line); text-align: center; color: var(--ls-soft); font-size: 15px; }
.ls .x-held-page .xm-card .xm-empty strong { color: var(--ls-ink); font-size: 17px; font-weight: 800; }
.ls .x-held-page .xm-card .xm-empty-icon { display: grid; place-items: center; width: 48px; height: 48px; margin-bottom: 6px; border-radius: 50%; color: var(--xs-on-bg); background: var(--xb-tone); }

/* the composer: attach, a field that grows to four lines, Send */
.ls .x-held-page .xm-card .xm-composer { gap: 8px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--ls-line); }
.ls .x-held-page .xm-card .xm-compose {
  display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; align-items: end; gap: 6px;
  padding: 4px; border-radius: 26px; background: var(--ls-canvas); box-shadow: inset 0 0 0 1.5px var(--xs-ring);
}
.ls .x-held-page .xm-card .xm-compose:focus-within { box-shadow: inset 0 0 0 2px var(--xs-on-bg); }
.ls .x-held-page .xm-card .xm-compose:has(textarea:focus-visible) { outline: 3px solid var(--ls-ink); outline-offset: 2px; }
.ls .x-held-page .xm-card .xm-compose .field { margin: 0; min-width: 0; }
.ls .x-held-page .xm-card .xm-compose textarea {
  display: block; width: 100%; min-height: 44px; max-height: 110px; margin: 0; padding: 11px 4px;
  border: 0; border-radius: 0; outline: 0; background: none; box-shadow: none; resize: none;
  color: var(--ls-ink); font: 500 16px/22px var(--tud-font-primary); field-sizing: content;
}
.ls .x-held-page .xm-card .xm-compose textarea::placeholder { color: var(--ls-soft); opacity: 1; }
.ls .x-held-page .xm-card .xm-attach { position: relative; display: grid; place-items: center; width: 44px; height: 44px; min-height: 0; padding: 0; border-radius: 50%; color: var(--ls-ink-2); background: none; cursor: pointer; }
.ls .x-held-page .xm-card .xm-attach:hover { color: var(--ls-ink); background: var(--xs-hover-bg); }
.ls .x-held-page .xm-card .xm-attach:has(input:focus-visible) { outline: 3px solid var(--ls-ink); outline-offset: 2px; }
.ls .x-held-page .xm-card .xm-send {
  min-width: 0; min-height: 44px; height: 44px; padding: 0 20px; border: 0; border-radius: 22px;
  color: var(--xs-on-ink); background: var(--xs-on-bg); font: 700 16px/1 var(--tud-font-primary); cursor: pointer;
}
.ls .x-held-page .xm-card .xm-send:hover:not(:disabled) { background: color-mix(in srgb, var(--xs-on-bg) 86%, #000); }
.ls .x-held-page .xm-card .xm-send:focus-visible { outline: 3px solid var(--ls-ink); outline-offset: 2px; }
.ls .x-held-page .xm-card .xm-send:disabled { color: var(--ls-soft); background: var(--ls-line); cursor: default; }
.ls .x-held-page .xm-card .xm-composer [data-attached]:empty, .ls .x-held-page .xm-card .xm-composer .form-msg:empty { display: none; }
.ls .x-held-page .xm-card .xm-composer [data-attached] { padding: 0 8px; font-size: 14px; }

@media (max-width: 899px) {
  .ls .x-held-page .xm-card .bk-thread { max-height: min(62vh, 460px); }
  .ls .x-held-page .xm-card .bk-msg { max-width: 88%; }
  .ls .x-held-page .xm-card .xm-send { padding: 0 16px; }
}
.ls .x-held-page .xm-card .xm-attach input { position: absolute; inset: 0; width: 100%; height: 100%; min-height: 0; margin: 0; padding: 0; border: 0; border-radius: 50%; opacity: 0; cursor: pointer; }
.ls .x-held-page .xm-card .xm-attach svg { position: relative; pointer-events: none; }

/* =========================================================================
   The calendar still (b.js): its day square black until a day and a time
   are chosen (a cut of the still's own square beside it), the orange day's
   pop layer and its glow, a sheen masked to the still, and the page that
   turns over the rings on a month change. All sit above the still's own
   wrappers (tilt.js lifts those to z-index 3) and move with it: the press
   and drag belong to the still's outer wrapper only, so no layer slips.
   ========================================================================= */
.xb-side .xb-model { position: relative; }
.xb-side .xb-model > .tud-tilt { transform: none !important; }
.xb-side .xb-model :is(.xd-off, .xd-cell, .xd-page) { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.xb-side .xb-model .xd-glow { position: absolute; z-index: 4; left: 29%; top: 50%; width: 32%; height: 29%; border-radius: 50%; opacity: 0; pointer-events: none;
  background: radial-gradient(closest-side, rgba(255, 92, 38, .38), rgba(255, 92, 38, .14) 60%, rgba(255, 92, 38, 0)); }
.xb-side .xb-model .xd-off { z-index: 5; }
.xb-side .xb-model.is-day-on .xd-off { opacity: 0; }
.xb-side .xb-model .xd-cell { z-index: 6; opacity: 0; transform-origin: 45.1% 64.4%; }
.xb-side .xb-model .xd-sheen { position: absolute; z-index: 7; inset: 0; overflow: hidden; pointer-events: none;
  -webkit-mask: url("/assets/img/models/campus-calendar.webp") 0 0 / 100% 100% no-repeat; mask: url("/assets/img/models/campus-calendar.webp") 0 0 / 100% 100% no-repeat; }
.xb-side .xb-model .xd-sheen span { position: absolute; inset: 0; opacity: 0;
  background: linear-gradient(105deg, rgba(255, 255, 255, 0) 30%, rgba(255, 255, 255, .22) 42%, rgba(255, 255, 255, .5) 50%, rgba(255, 255, 255, .22) 58%, rgba(255, 255, 255, 0) 70%); }
[data-theme="dark"] .xb-side .xb-model .xd-sheen span { background: linear-gradient(105deg, rgba(255, 255, 255, 0) 30%, rgba(255, 255, 255, .12) 42%, rgba(255, 255, 255, .26) 50%, rgba(255, 255, 255, .12) 58%, rgba(255, 255, 255, 0) 70%); }
/* the turning page: hinged on the ring line, its back never shown */
.xb-side .xb-model .xd-flip { position: absolute; z-index: 8; inset: 0; opacity: 0; pointer-events: none; perspective: 380px; perspective-origin: 50% 0; }
.xb-side .xb-model .xd-leaf { position: absolute; inset: 0; transform-origin: 50% 13%; backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.xb-side .xb-model .xd-leaf.is-off .xd-page--on, .xb-side .xb-model .xd-leaf:not(.is-off) .xd-page--off { visibility: hidden; }
.xb-side .xb-model :is(.xd-shade, .xd-under) { position: absolute; inset: 0; opacity: 0;
  -webkit-mask: url("/assets/img/models/campus-calendar-page.webp") 0 0 / 100% 100% no-repeat; mask: url("/assets/img/models/campus-calendar-page.webp") 0 0 / 100% 100% no-repeat; }
.xb-side .xb-model .xd-shade { background: linear-gradient(to bottom, rgba(20, 16, 12, .55), rgba(20, 16, 12, .85)); }
.xb-side .xb-model .xd-under { background: linear-gradient(to bottom, rgba(20, 16, 12, .7), rgba(20, 16, 12, 0) 55%); }
@media (prefers-reduced-motion: reduce) { .xb-side .xb-model :is(.xd-cell, .xd-glow, .xd-sheen, .xd-flip) { display: none; } }

/* =========================================================================
   The booking QR (b.js): a light ticket tile in every theme, the code with
   its quiet zone, a short caption, the pitch hem along the foot.
   ========================================================================= */
.x-held-page .xq-tile { position: relative; display: grid; justify-items: center; gap: 2px; width: min(100%, 236px); margin: 18px auto 22px; padding: 10px 10px 26px; overflow: hidden; border-radius: 18px; background: #fff; box-shadow: 0 0 0 1px #E6DDD0, var(--tud-shadow-card); }
.x-held-page .xq-tile .bk-qr { width: 100%; margin: 0; padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none; }
.x-held-page .xq-tile .bk-qr svg.xq-code { display: block; width: 100%; height: auto; }
.x-held-page .xq-cap { margin: 0; color: #3A362F; font-size: 14px; font-weight: 700; line-height: 1.3; text-align: center; }
.x-held-page.brand-custom .xq-tile > .brand-band.xq-hem { position: absolute; left: 0; right: 0; bottom: 0; height: 12px; }

/* the live calendar (b3d.js): a canvas over the still, reaching past its box so a page can turn over the top, placed
   absolutely so nothing moves. The still shows until the model's first frame, then the canvas fades in over it and
   the still goes once the canvas is fully there. Never a target, never focusable. */
.xb-side .xb-model > .xd-live { position: absolute; z-index: 9; display: block; pointer-events: none; opacity: 0; transition: opacity .22s ease-out; }
.xb-side .xb-model.is-live > .xd-live { opacity: 1; }
.xb-side .xb-model.is-live > :not(.xd-live) { opacity: 0; transition: opacity 0s linear .24s; }
/* the request page's envelope (public/assets/booking-envelope.js) uses the same canvas; with reduced motion it stays
   hidden over the still and the two cross-fade, the closed envelope while the request goes, the waiting model once it
   lands (public/assets/booking-waiting.js, its own canvas in the same box), the still again if it fails */
.xb-side .xb-model--quote:not(.is-live) > :not(.xd-live) { transition: opacity .2s ease; }
.xb-side .xb-model--quote.is-sealed:not(.is-live) > :not(.xd-live) { opacity: 0; }
/* the sent page's waiting model (public/assets/booking-waiting.js): the review tray with the sealed request, wider
   than the portrait stills so it weighs the same; the space above it is the request's, gliding in from there on
   arrival. Played over its still the same way (reduced motion keeps the still) */
.xb-tside-head .x-model--wait { position: relative; width: 196px; margin-top: 32px; }
.xb-tside-head .x-model--wait > .xd-live { position: absolute; z-index: 9; display: block; pointer-events: none; }
.xb-tside-head .x-model--wait.is-live > :not(.xd-live) { opacity: 0; transition: opacity 0s linear .24s; }
/* arriving from the request page: the still stays out of sight while the model picks up from its first frame */
.xb-tside-head .x-model--wait.is-arriving > :not(.xd-live) { visibility: hidden; }
@media (max-width: 899px) { .xb-tside-head .x-model--wait { width: 176px; margin-top: 28px; } }

/* =========================================================================
   No time before a day (Update 20): until a day is picked, the Time column
   holds one quiet line in a dashed well, no hours; it fills the column
   beside the month and is a short strip under it when stacked.
   ========================================================================= */
.xb-wait { display: flex; flex: 1 1 auto; align-items: center; justify-content: center; gap: 10px; min-height: 120px; margin: 0; padding: 16px 20px; border: 1.5px dashed var(--ls-line-2); border-radius: var(--xs-r); color: var(--ls-ink-2); font-size: 16px; font-weight: 700; line-height: 1.3; text-align: center; }
.xb-wait[hidden] { display: none; }
.xb-wait svg { flex: none; color: var(--xb-text); }
@media (max-width: 999px) { .xb-wait { flex: none; min-height: 64px; } }

/* =========================================================================
   Update 22: per brand. A plain hem where the brand has no pattern; the
   initials disc for a brand with no logo; the no-photo wall page (the logo
   disc on the brand's colour beside the template's doodle, upright, whole);
   dated departures as the same selector chips; the seats picker; the quote
   request form in the same family.
   ========================================================================= */
.brand-custom.xb[data-brand-pattern="none"] .brand-band,
.brand-custom.x-held-page[data-brand-pattern="none"] .brand-band { display: block; height: 10px; background: var(--brand-band, var(--xb-on)); }
.brand-custom.xb[data-brand-pattern="none"] .xb-side > .brand-band,
.brand-custom.x-held-page[data-brand-pattern="none"] :is(.xb-tside > .brand-band, .xq-hem) { height: 8px; }

.xb-initials { display: grid !important; place-items: center; background: var(--xb-on) !important; color: var(--xb-on-ink); font-family: var(--tud-font-secondary); font-weight: 800; letter-spacing: -0.02em; }
.xb-wall-logo.xb-initials { font-size: 26px; }
.x-held-page .x-brandlogo.xb-initials { font-size: 17px; }
.ls .x-held-page .xm-card .xm-disc.xb-initials { font-size: 12px; }

/* the no-photo page hangs upright: the disc and the doodle, nothing cropped */
.xb-wall--plain .xb-wall-sheet { transform: none; }
.xb-wall--plain { padding-right: 0; }
.xb-wall-plain { display: grid !important; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); align-items: center; gap: 4%; padding: 6% 7%; background: var(--xb-tone) !important; box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--xb-on) 18%, transparent); }
.xb-plain-disc { display: grid; place-items: center; width: 100%; aspect-ratio: 1; overflow: hidden; border-radius: 50%; background: #000; box-shadow: 0 0 0 5px var(--ls-paper), 0 0 0 8px var(--xb-on); }
.xb-plain-disc img { display: block; width: 100%; height: 100%; object-fit: cover; }
.xb-plain-disc.xb-initials { font-size: clamp(34px, 4.4vw, 58px); }
.xb-plain-art { display: block; justify-self: center; width: 100%; }
.xb-plain-art img { display: block; width: 100%; height: auto; max-height: 190px; object-fit: contain; }
[data-theme="dark"] .xb-wall-plain .theme-art-light { display: none; }
.xb-wall--plain .xb-wall-foot { grid-template-columns: minmax(0, 1fr); padding-top: 14px; }

/* "From" before a price when the tiers differ */
.xb-from { align-self: baseline; color: var(--ls-ink-2); font-size: 15px; font-weight: 700; }

/* dated departures: one chip per departure, the dates, when and where it leaves, each tier's price, seats left */
.xb .xb-deps .bkp-time-face { display: grid; place-items: stretch; align-content: start; gap: 6px; height: auto; padding: 14px 16px; text-align: left; }
.xb-dep-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 4px 10px; }
.xb-dep-when { color: var(--xs-ink); font-family: var(--tud-font-secondary); font-size: 18px; font-weight: 700; letter-spacing: -0.01em; }
.xb-dep-left { padding: 3px 10px; border-radius: 999px; color: var(--xs-ink); font-size: 13px; font-weight: 800; box-shadow: inset 0 0 0 1.5px var(--xs-ring); }
.xb-dep-left.is-few { background: var(--xb-tone); box-shadow: inset 0 0 0 1.5px var(--xb-hover-ring); }
.xb-dep-meta { color: var(--xs-ink-2); font-family: var(--tud-font-primary); font-size: 15px; font-weight: 600; }
.xb-dep-tiers { display: grid; gap: 2px; padding-top: 8px; border-top: 1.5px dashed var(--ls-line-2); }
.xb-dep-tier { display: flex; justify-content: space-between; gap: 10px; color: var(--xs-ink-2); font-family: var(--tud-font-primary); font-size: 15px; font-weight: 600; }
.xb-dep-tier b { color: var(--xs-ink); font-family: var(--tud-font-secondary); font-weight: 700; }
.xb.bk-page .xb-deps .bkp-time input:checked + * .xb-dep-left { background: none; box-shadow: inset 0 0 0 1.5px var(--xs-on-ink); }
.xb.bk-page .xb-deps .bkp-time input:checked + * .xb-dep-tiers { border-top-color: color-mix(in srgb, var(--xs-on-ink) 45%, transparent); }
.xb.bk-page .xb-deps .bkp-time input:checked + * .xb-dep-tier b { color: var(--xs-on-ink-2); }
@media (max-width: 999px) { .xb--departures .xb-times-list { grid-template-columns: minmax(0, 1fr); } }

/* the seats picker: a chip per tier, the stepper on its right */
.xb .xb-tiers { display: grid; gap: 8px; margin: 0; }
.xb .xb-tiers > .bkp-label { margin: 0 0 2px; }
.xb .xb-tier { display: flex; justify-content: space-between; align-items: center; gap: 12px; min-height: 64px; padding: 8px 8px 8px 16px; border-radius: var(--xs-r); background: var(--xs-bg); box-shadow: inset 0 0 0 1.5px var(--xs-ring); transition: background-color 140ms ease, box-shadow 140ms ease; }
.xb .xb-tier.is-on { background: var(--xb-tone); box-shadow: inset 0 0 0 2px var(--xs-on-bg); }
.xb-tier-copy { display: grid; gap: 2px; min-width: 0; }
.xb-tier-copy strong { font-size: 16px; font-weight: 800; }
.xb-tier-price { color: var(--ls-ink-2); font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }
.xb .xb-stepper { display: flex; align-items: center; gap: 4px; }
.xb .xb-stepper .qty-btn { display: grid; place-items: center; width: 44px; height: 44px; border: 0; border-radius: 10px; color: var(--xs-on-ink); background: var(--xs-on-bg); cursor: pointer; }
.xb .xb-stepper .qty-btn:focus-visible { outline: 3px solid var(--ls-ink); outline-offset: 2px; }
.xb .xb-stepper .qty-value { min-width: 28px; text-align: center; font-family: var(--tud-font-secondary); font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; }
.xb .xb-tiers.is-invalid .xb-tier { box-shadow: inset 0 0 0 2px var(--tud-color-danger, #B3261E); }

/* the about block for an offering that has a description or included lines */
.xb-about { display: grid; gap: 18px; margin-bottom: 18px; }
.xb-prose p { margin: 0 0 10px; color: var(--ls-ink-2); font-size: 16px; line-height: 1.55; }
.xb-prose p:last-child { margin: 0; }
.xb-incl { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.xb-incl > div { display: grid; align-content: start; gap: 8px; padding: 18px 20px; border-radius: 18px; background: var(--ls-canvas); box-shadow: inset 0 0 0 1px var(--ls-line); }
@media (max-width: 899px) { .xb-incl { grid-template-columns: minmax(0, 1fr); } }

/* a quote request: the brand's form fields where the month and the hours were */
.xb-board--quote { grid-template-areas: "work side" "info side"; grid-template-rows: auto 1fr; }
.xb-board--quote > .xb-quote { grid-area: work; display: grid !important; grid-template-columns: minmax(0, 1fr); gap: 20px; }
.xb-quote-h { margin: 0; font-size: 22px !important; letter-spacing: -0.02em; }
.xb-quote .field { display: grid; gap: 8px; margin: 0; padding: 0; border: 0; min-width: 0; }
.xb-quote .field-label { font-size: 15px; font-weight: 800; color: var(--ls-ink); }
.xb-quote .field-optional { color: var(--ls-ink-2); font-weight: 600; }
.xb-quote .field-hint { color: var(--ls-ink-2); font-size: 14px; }
.xb-quote .field-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.xb-quote :is(input[type="text"], input[type="number"], input[type="date"], textarea) { box-sizing: border-box; width: 100%; min-height: var(--xs-h); padding: 12px 14px; border: 0; background: var(--xs-bg); color: var(--xs-ink); font: 600 16px/1.4 var(--tud-font-primary); box-shadow: inset 0 0 0 1.5px var(--xs-ring); }
.xb-quote :is(input, textarea):hover { box-shadow: inset 0 0 0 2px var(--xs-hover-ring); }
.xb-quote :is(input, textarea):focus-visible { outline: 3px solid var(--ls-ink); outline-offset: 2px; }
.xb-quote .bk-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.xb-quote .paid-option { position: relative; display: inline-flex; cursor: pointer; }
.xb-quote .paid-option input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }
.xb-quote .paid-option span { display: inline-flex; align-items: center; min-height: var(--xs-h); padding: 0 18px; border-radius: var(--xs-r); background: var(--xs-bg); color: var(--xs-ink); font-size: 16px; font-weight: 700; box-shadow: inset 0 0 0 1.5px var(--xs-ring); transition: background-color 140ms ease, box-shadow 140ms ease, color 140ms ease; }
.xb-quote .paid-option:hover input:not(:checked) + span { background: var(--xs-hover-bg); box-shadow: inset 0 0 0 2px var(--xs-hover-ring); }
.xb-quote .paid-option input:checked + span { color: var(--xs-on-ink); background: var(--xs-on-bg); box-shadow: inset 0 0 0 2px var(--xs-on-bg); }
.xb-quote .paid-option input:focus-visible + span { outline: 3px solid var(--ls-ink); outline-offset: 2px; }
.xb-quote .bk-check { display: inline-flex; align-items: center; gap: 10px; font-size: 15px; font-weight: 600; }
.xb-quote .bk-check input { width: 20px; height: 20px; accent-color: var(--xs-on-bg); }
.xb-side-head--quote .xb-price-for { max-width: 26ch; margin: 0 auto; }
.xb--quote .xb-side .bkp-fine { margin: 10px 0 0; color: var(--ls-ink-2); font-size: 14px; }
@media (max-width: 899px) {
  .xb-board--quote { grid-template-areas: "work" "side" "info"; }
  .xb-quote .field-row { grid-template-columns: minmax(0, 1fr); }
}
/* a price the brand confirms at booking: one optional note above the button */
.xb .xb-note { display: grid; gap: 8px; }
.xb .xb-note textarea { min-height: 88px; }

/* =========================================================================
   Update 23. B reuses the live page's class names (bk-form, paid-option,
   bk-msg) so bookings.js keeps working; the site's own rules for them
   (bookings.css, shop.css, site-launch.css) still reach B's markup. Each is
   reset here where B draws the part itself, so only one style shows.
   ========================================================================= */
/* the request form is the board, not a 640 px form column */
.xb-board.bk-form { max-width: none; row-gap: 0; column-gap: clamp(28px, 3.5vw, 56px); }
.xb-board--quote > .xb-quote { max-width: 640px; }
/* one chip per choice: the label is only a hit area, the span is the chip */
.ls .xb-quote .bk-chips { gap: 8px; }
.ls .xb-quote .bk-chips .paid-option,
.ls .xb-quote .bk-chips .paid-option:has(input:checked) { min-height: 0; padding: 0; border: 0; border-radius: 0; color: inherit; background: none; box-shadow: none; font-weight: inherit; }
.ls .xb-quote .bk-chips .paid-option:has(input:focus-visible) { outline: 0; }
/* fields: whole dates, labels on one line */
.xb-quote .field-row { gap: 12px; }
.xb-quote .field-row .field-label { white-space: nowrap; }
.xb-quote input[type="date"] { min-width: 0; padding-right: 10px; font-variant-numeric: tabular-nums; }
.xb-quote input::placeholder, .xb-quote textarea::placeholder { color: #93887E; opacity: 1; }
/* the request panel: the button first, no rule above it */
.xb--quote .xb-summary { padding-top: 0 !important; border-top: 0; }
/* the panel price: "From" and the old price stay whole and wrap below, never letter by letter */
.xb-price-now { flex-wrap: wrap; row-gap: 2px; }
.xb-price-now > .xb-from, .xb-price-now > s { flex: none; white-space: nowrap; }

/* =========================================================================
   Update 24: dark mode. The site's own switch (tud_theme, the header moon)
   drives it; the colours are the site's dark tokens and the brand's dark
   palette through brand-kit.js. Nothing here touches light.
   ========================================================================= */
/* the 3D calendar is an object, not a surface: its cream paper and orange stay, a touch dimmer so it does not glow on a
   dark ground, with the kit's card edge (its ink line plus a thin cream rim) and a shadow that still reads */
[data-theme="dark"] :is(.xb-side .xb-model, .xb-tside-head .x-model):has(img[src*="campus-calendar"]) img.x-model-light { display: block !important; }
[data-theme="dark"] :is(.xb-side .xb-model, .xb-tside-head .x-model):has(img[src*="campus-calendar"]) img.x-model-dark { display: none !important; }
[data-theme="dark"] :is(.xb-side .xb-model, .xb-tside-head .x-model):not(.is-live):has(img[src*="campus-calendar"]) {
  filter: brightness(.93) drop-shadow(1px 0 0 rgba(250, 247, 242, .7)) drop-shadow(-1px 0 0 rgba(250, 247, 242, .7)) drop-shadow(0 1px 0 rgba(250, 247, 242, .7)) drop-shadow(0 -1px 0 rgba(250, 247, 242, .7)) drop-shadow(0 10px 12px rgba(0, 0, 0, .5)); }
/* Update 25: the request page's date digits in dark take the normal text colour. WebKit paints an empty date's digit
   fields in its own placeholder tone, gold on the dark ground; the fill colour reaches into them */
[data-theme="dark"] .xb-quote input[type="date"] { -webkit-text-fill-color: var(--ls-ink); }

/* =========================================================================
   Update 25: booking part 2 on the page. A day or peak price names itself
   (under the day, on the departure), seats left come from the API, a day the
   brand closed is struck through, the Paying card lists the ways to pay, the
   total is the server's preview (its message in place of it when the choice
   cannot be booked), and a brand with a request form offers it.
   ========================================================================= */
.xb-times-rule { display: block; margin-top: 2px; color: var(--xb-text); font-family: var(--tud-font-primary); font-size: 14px; font-weight: 700; letter-spacing: 0; }
.xb-dep-rule { justify-self: start; padding: 2px 9px; border-radius: 999px; color: var(--xs-ink); background: var(--xb-tone); font-family: var(--tud-font-primary); font-size: 13px; font-weight: 800; }
.xb.bk-page .xb-deps .bkp-time input:checked + * .xb-dep-rule { color: var(--xs-on-ink); background: none; box-shadow: inset 0 0 0 1.5px var(--xs-on-ink); }
.xb .xb-cell--closed { text-decoration: line-through; text-decoration-thickness: 1.5px; }
.xb-card .xb-ways { grid-column: -2 / -1; margin-top: 0; color: var(--ls-ink); font-weight: 700; }
.xb-ask { margin: 14px 0 0; font-size: 16px; font-weight: 700; }
.xb-ask a { color: var(--ls-ink); text-decoration-thickness: 2px; text-underline-offset: 4px; text-decoration-color: var(--xb-text); }
.xb-summary .bkp-total small.xb-cuts { margin-top: 2px; }
.xb-summary .bkp-total[aria-busy="true"] { opacity: .55; }
/* Update 26: the price line while it loads and when it cannot be shown. It takes the whole row under the summary,
   left aligned with it, and keeps the price's own line height, so nothing moves when the answer comes. */
.xb-summary .bkp-total:is(.is-wait, .is-msg) { display: flex; flex: 1 1 100%; align-items: center; min-height: 1lh; text-align: left; white-space: normal; }
.xb-summary .bkp-total.is-wait[aria-busy="true"] { opacity: 1; }
.xb-summary .bkp-total[tabindex="-1"]:focus { outline: none; }
.xb-summary .bkp-total .xb-price-wait { display: block; width: min(7em, 100%); height: .7em; border-radius: 8px; background: var(--ls-line-2); }
@media (prefers-reduced-motion: no-preference) {
  .xb-summary .bkp-total .xb-price-wait { animation: xb-price-breathe 1.8s ease-in-out infinite alternate; }
}
@keyframes xb-price-breathe { from { opacity: 1; } to { opacity: .5; } }
.xb-summary .bkp-total .xb-price-msg { display: block; max-width: 34ch; margin: 0; color: var(--ls-soft); font-family: var(--tud-font-primary); font-size: 15px; font-weight: 600; line-height: 1.4; text-align: left; white-space: normal; text-wrap: pretty; }
/* a text button with a 44px hit area that adds no height to the line */
.xb-summary .bkp-total .xb-price-retry { position: relative; display: inline-block; min-height: 24px; margin: 0 0 0 2px; padding: 0 4px; border: 0; border-radius: 6px; color: var(--ls-ink); background: none; font: inherit; font-weight: 700; line-height: 24px; text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 3px; cursor: pointer; }
.xb-summary .bkp-total .xb-price-retry::after { content: ""; position: absolute; inset: -10px -8px; }
.xb-summary .bkp-total .xb-price-retry:hover { text-decoration-thickness: 2.5px; }
.xb-summary .bkp-total .xb-price-retry:focus-visible { outline: 2px solid var(--ls-ink); outline-offset: 2px; }
.ls .x-held-page .pay-method--cash .pay-cash { margin: 4px 0 0; color: var(--ls-ink-2); font-size: 15px; line-height: 1.45; }
