/*
 * Base layer shared by every template.
 *
 * It only ships a reset, the boot/error states, and the design tokens a
 * provider's theme fills in. Everything visual belongs to the template's own
 * stylesheet, so a template can restyle the page completely without fighting
 * anything here.
 */

:root {
  /* Filled in from providerSites/{siteId}.theme by the renderer. The values
     here are the fallbacks a template gets when the provider left a field
     blank. */
  --brand: #6366f1;
  --brand-contrast: #ffffff;
  --accent: #f59e0b;
  --bg: #ffffff;
  --surface: #f6f7fb;
  --surface-2: #eceef6;
  --text: #10131c;
  --text-muted: #5b6478;
  --border: #dfe3ee;
  --radius: 14px;
  --radius-sm: 9px;
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-heading: var(--font-body);
  --maxw: 1140px;
}

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; }
button { font: inherit; }
[hidden] { display: none !important; }

h1, h2, h3, h4 {
  font-family: var(--font-heading);
  line-height: 1.2;
  margin: 0 0 0.4em;
}

/* ---------- boot + failure states ---------- */

.boot {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 32px;
  text-align: center;
  color: var(--text-muted);
  background: var(--bg);
}

.boot__spinner {
  width: 30px;
  height: 30px;
  border: 3px solid color-mix(in srgb, var(--brand) 25%, transparent);
  border-top-color: var(--brand);
  border-radius: 50%;
  animation: xdSpin 0.7s linear infinite;
}

@keyframes xdSpin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .boot__spinner { animation-duration: 2s; }
  * { scroll-behavior: auto !important; }
}

.state {
  max-width: 460px;
  margin: 0 auto;
}

.state h1 {
  font-size: 22px;
  color: var(--text);
}

.state p {
  margin: 0 0 18px;
  font-size: 15px;
}

.state code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 2px 6px;
}

.state__link {
  display: inline-block;
  padding: 11px 22px;
  border-radius: var(--radius-sm);
  background: var(--brand);
  color: var(--brand-contrast);
  font-weight: 600;
  text-decoration: none;
}

/* A published site is only ever shown on its own domain; anything else gets
   the neutral states above, so nothing here leaks a provider's branding. */

/* =======================================================================
 * Account panel
 *
 * Owned by the runtime, not by any template, so sign in and sign up work
 * on every design. It is styled from the same theme tokens a template
 * uses, so it reads as part of whatever site it opens over.
 * ===================================================================== */

.xd-auth {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  padding: 20px;
}

.xd-auth__scrim {
  position: absolute;
  inset: 0;
  background: rgba(8, 11, 18, 0.55);
  backdrop-filter: blur(2px);
}

.xd-auth__panel {
  position: relative;
  width: 100%;
  max-width: 420px;
  max-height: calc(100dvh - 40px);
  overflow-y: auto;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 28px 26px 22px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.28);
}

.xd-auth__x {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 44px;
  height: 44px;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  border-radius: 8px;
}
.xd-auth__x:hover { background: var(--surface); color: var(--text); }

.xd-auth__panel h2 {
  font-family: var(--font-heading);
  font-size: 22px;
  margin: 0 0 4px;
}

.xd-auth__lede {
  margin: 0 0 18px;
  color: var(--text-muted);
  font-size: 14px;
}

.xd-auth__panel form { display: grid; gap: 13px; }

.xd-auth__panel label {
  display: grid;
  gap: 5px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}

.xd-auth__panel input,
.xd-auth__panel textarea {
  font: inherit;
  font-weight: 400;
  width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
}
.xd-auth__panel input:focus-visible,
.xd-auth__panel textarea:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 1px;
}

.xd-auth__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 11px;
}
@media (max-width: 420px) {
  .xd-auth__row { grid-template-columns: 1fr; }
}

.xd-auth__submit {
  margin-top: 4px;
  padding: 13px 20px;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--brand);
  color: var(--brand-contrast);
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}
.xd-auth__submit:disabled { opacity: 0.6; cursor: progress; }

.xd-auth__ghost {
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-muted);
  font-size: 14px;
  cursor: pointer;
}

.xd-auth__links {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 14px;
  font-size: 13.5px;
}

.xd-auth__foot {
  margin: 14px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: 13.5px;
  color: var(--text-muted);
}

.xd-auth a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--brand);
  text-decoration: none;
  font-weight: 600;
}
.xd-auth a:hover { text-decoration: underline; }

.xd-auth__msg {
  margin: 0 0 16px;
  padding: 10px 13px;
  border-radius: var(--radius-sm);
  font-size: 13.5px;
  font-weight: 600;
}
.xd-auth__msg--ok { background: #ecfdf5; color: #065f46; }
.xd-auth__msg--error { background: #fef2f2; color: #991b1b; }

/* ---------- account area: orders, receipts, the delivery pin ----------
   Part of the runtime panel, not of any template, so every design gets
   the same place for a customer to find what they've bought. */

.xd-auth__tabs {
  display: flex;
  gap: 6px;
  /* Clears the close button, which is absolutely positioned over this row. */
  padding-right: 44px;
  margin: 0 0 18px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}

.xd-auth__tab {
  flex: 1;
  min-height: 44px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
  color: var(--text-muted);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.xd-auth__tab.is-on {
  background: var(--brand);
  border-color: transparent;
  color: var(--brand-contrast);
}

.xd-auth__hint { color: var(--text-muted); font-weight: 400; }
/* "This number already has an account" under the phone field. */
.xd-auth__hint--warn { color: #991b1b; font-weight: 600; font-size: 13px; margin: 0; }
.xd-auth__hint--warn[hidden] { display: none; }
.xd-auth__hint--warn a { display: inline; color: inherit; text-decoration: underline; }

/* Country picker and the dial-code-prefixed number field. */
.xd-auth__panel select {
  font: inherit;
  font-weight: 400;
  width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
}
.xd-auth__panel select:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 1px;
}
.xd-phone { display: flex; align-items: stretch; }
.xd-phone__dial {
  display: flex;
  align-items: center;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-right: 0;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  background: var(--surface);
  color: var(--text-muted);
  font-weight: 600;
  white-space: nowrap;
}
.xd-phone input { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; min-width: 0; }

.xd-list { list-style: none; margin: 0; padding: 0; }

.xd-list__row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  padding: 13px 0;
  border-top: 1px solid var(--border);
}
.xd-list__row:first-child { border-top: 0; }

.xd-list__main { display: grid; gap: 2px; min-width: 0; text-align: left; }
.xd-list__title { font-weight: 600; }
.xd-list__meta { color: var(--text-muted); font-size: 13px; }

.xd-list__end {
  display: grid;
  gap: 5px;
  justify-items: end;
  text-align: right;
  flex: 0 0 auto;
}
.xd-list__amount { font-weight: 700; white-space: nowrap; }

.xd-badge {
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

/* A whole receipt row is the target, so it clears 44px without a tiny chevron
   being the only thing you can hit. */
.xd-list__pick {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  text-align: left;
}
.xd-list__chev { color: var(--text-muted); font-size: 20px; }

.xd-linkbtn {
  min-height: 44px;
  padding: 0 2px;
  border: 0;
  background: none;
  color: var(--brand);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.xd-pin {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.xd-pin__label { display: block; font-size: 13px; font-weight: 600; }
.xd-pin__value { display: block; color: var(--text-muted); font-size: 13px; }

/* ---------- saved places: the Home and Office pinned in the apps ---------- */

.xd-places__head { margin: 6px 0 2px; font-size: 15px; }

.xd-place {
  display: grid;
  gap: 10px;
  padding: 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.xd-place.is-chosen {
  border-color: var(--brand);
  box-shadow: 0 0 0 1px var(--brand) inset;
}

.xd-place__top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.xd-place__name { font-size: 15px; font-weight: 700; }

.xd-place__choose {
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.xd-place__choose.is-chosen {
  background: var(--brand);
  border-color: transparent;
  color: var(--brand-contrast);
}

.xd-place__field { gap: 4px; }

/* ---------- read-only details ---------- */

.xd-details { display: grid; gap: 0; margin: 0 0 4px; }

.xd-detail {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  padding: 11px 0;
  border-top: 1px solid var(--border);
}
.xd-detail:first-child { border-top: 0; }
.xd-detail__label { flex: 0 0 auto; font-size: 13px; color: var(--text-muted); }
.xd-detail__value { text-align: right; font-weight: 600; white-space: pre-line; }

.xd-place__where { margin: 0; }
.xd-place__pin { margin: 0; font-size: 13px; color: var(--text-muted); }

/* ---------- the second OTP channel ---------- */

.xd-otp__alts { display: grid; gap: 8px; }
.xd-otp__alts button[disabled] { opacity: 0.55; cursor: default; }

/* Firebase's reCAPTCHA, on its own layer above the panel so a repaint of the
   panel cannot tear the challenge down while it is being solved. */
.xd-captcha {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(6, 11, 24, 0.55);
}
.xd-captcha__box {
  max-width: 340px;
  padding: 18px;
  border-radius: var(--radius);
  background: var(--bg);
  text-align: center;
}
.xd-captcha__lede { margin: 0 0 12px; font-size: 14px; color: var(--text-muted); }

/* ---------- the delivery quote, injected into every template's checkout ---- */

.xd-quote {
  display: grid;
  gap: 6px;
  padding: 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.xd-quote:empty { display: none; }

.xd-quote__row { display: flex; justify-content: space-between; gap: 12px; font-size: 14px; }
.xd-quote__row.is-total {
  padding-top: 8px;
  border-top: 1px solid var(--border);
  font-size: 16px;
  font-weight: 700;
}
.xd-quote__note { margin: 0; font-size: 13px; color: var(--text-muted); }
.xd-quote__note--warn { color: var(--text); font-weight: 600; }

/* How the delivery charge was reached — the shop's bundles, free shipping,
   size tiers or zone, in its own words, under the Delivery line. */
.xd-quote__sub {
  margin: 0 0 0 2px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-muted);
}

/* ---------- where the order goes, chosen at the checkout ---------- */

/* The doubled class is deliberate: a template styles its own `.x-form input`,
   which would otherwise outrank a single class and leave a locked field
   looking exactly like an editable one. */
.xd-locked.xd-locked {
  background: var(--surface);
  color: var(--text-muted);
  cursor: default;
}

.xd-deliver { display: grid; gap: 9px; }
.xd-deliver__head { margin: 0; font-size: 14px; font-weight: 700; }

.xd-deliver__opts {
  display: grid;
  gap: 8px;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
}

.xd-deliver__opt {
  display: grid;
  gap: 3px;
  padding: 10px 12px;
  min-height: 44px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.xd-deliver__opt.is-on {
  border-color: var(--accent, currentColor);
  box-shadow: inset 0 0 0 1px var(--accent, currentColor);
}
.xd-deliver__name { font-size: 14px; font-weight: 600; }
.xd-deliver__where { font-size: 12.5px; line-height: 1.4; color: var(--text-muted); }
.xd-deliver__none { font-style: italic; }
.xd-deliver__pin {
  font-size: 11.5px;
  line-height: 1.3;
  color: var(--text-muted);
  opacity: 0.85;
}

/* ---------- paying for a website order ---------- */

.xd-order__track {
  margin: 0;
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--text-muted);
}
.xd-order__track strong { color: var(--text); font-variant-numeric: tabular-nums; }

.xd-pay {
  display: grid;
  gap: 8px;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
}

.xd-pay__opt {
  display: grid;
  gap: 3px;
  padding: 11px 13px;
  min-height: 44px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.xd-pay__opt:hover { border-color: var(--brand); }
.xd-pay__name { font-size: 14px; font-weight: 700; }
.xd-pay__note { font-size: 12.5px; line-height: 1.4; color: var(--text-muted); }

.xd-bank {
  display: grid;
  gap: 6px;
  padding: 12px 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.xd-bank__head { margin: 0 0 2px; font-size: 14px; font-weight: 700; }
.xd-bank__row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 13.5px;
}
.xd-bank__row span:last-child {
  font-weight: 600;
  text-align: right;
  word-break: break-all;
  font-variant-numeric: tabular-nums;
}

/* ---------- flash sale and promo badges (h.badges) ---------- */

/* Fixed colours rather than the theme's: a sale badge has to read as a sale
   on every design, light or dark, and both pairs hold 4.5:1. */
.xd-badges { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 4px; }
.xd-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.xd-badge--flash { background: #b91c1c; color: #fff; }
.xd-badge--promo { background: #fde68a; color: #7c2d12; }
.xd-badge__clock { font-variant-numeric: tabular-nums; font-weight: 800; }

/* ---------- the shop's promo code ---------- */

.xd-promo { display: grid; gap: 6px; }

.xd-promo__row { display: flex; gap: 8px; align-items: stretch; }

/* The doubled class beats a template's own `.x-form input`, which would
   otherwise stretch this to full width on its own line. */
.xd-promo__input.xd-promo__input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  text-transform: uppercase;
}
/* Codes are upper case; the prompt for one should not be shouted. */
.xd-promo__input::placeholder { text-transform: none; }

.xd-promo__apply {
  flex: none;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.xd-promo__apply:disabled { opacity: 0.5; cursor: default; }

.xd-promo__on {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: 14px;
}
.xd-promo__code { flex: 1 1 auto; }

/* ---------- the map a delivery pin is dropped on ---------- */

.xd-map {
  position: fixed;
  inset: 0;
  /* Above the account panel, which is where it is opened from. */
  z-index: 1100;
  display: grid;
  place-items: center;
  padding: 16px;
}

.xd-map__scrim {
  position: absolute;
  inset: 0;
  background: rgba(8, 11, 18, 0.6);
}

.xd-map__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 560px;
  height: min(640px, calc(100dvh - 32px));
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.3);
}

.xd-map__head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 14px 12px 18px;
  border-bottom: 1px solid var(--border);
}
.xd-map__title { margin: 0; font-size: 18px; }
.xd-map__lede { margin: 2px 0 0; font-size: 13px; color: var(--text-muted); }

.xd-map__x {
  flex: none;
  width: 44px;
  height: 44px;
  margin: -6px -6px 0 auto;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  border-radius: 8px;
}

/* Leaflet needs a sized box before it will draw anything. */
.xd-map__canvas { flex: 1 1 auto; min-height: 240px; }

.xd-map__foot {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 12px 18px 14px;
  border-top: 1px solid var(--border);
}

.xd-map__coords {
  flex: 1 1 140px;
  margin: 0;
  font-size: 13.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.xd-map__actions { display: flex; gap: 8px; margin-left: auto; }

.xd-map__ghost,
.xd-map__save {
  min-height: 44px;
  padding: 0 16px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.xd-map__ghost {
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-muted);
}
.xd-map__save {
  border: none;
  background: var(--brand);
  color: var(--brand-contrast);
}
.xd-map__save:disabled { opacity: 0.55; cursor: not-allowed; }

/* ---------- an order, with what's happening and what's owed ---------- */

.xd-list--orders { display: grid; gap: 12px; }

.xd-order {
  display: grid;
  gap: 9px;
  padding: 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.xd-order__top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.xd-order__story { margin: 0; font-size: 13px; color: var(--text-muted); }

/* Who shared the code that is taking money off this basket. */
.xd-promo__by {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  font-weight: 400;
  color: var(--text-muted);
}

/*
 * Why the shop turned an order down, in their words.
 *
 * Built from the theme's own tokens rather than a red of its own: every
 * provider site restyles these, and a hardcoded colour would be the one thing
 * on the page that ignored the shop's design. It also avoids color-mix, which
 * the in-app browsers these links are opened in do not all support.
 */
.xd-order__reason {
  margin: 0;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border-left: 3px solid var(--text);
  font-size: 13px;
  line-height: 1.45;
}
.xd-order__reason strong { font-weight: 700; }

/* The receipt for an order just placed, on the page its basket just left. */
.xd-placed {
  margin: 0 0 20px;
  padding: 16px 18px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface, transparent);
}
.xd-placed__title { margin: 0 0 6px; font-size: 17px; }
.xd-placed__body { margin: 0; font-size: 14px; line-height: 1.5; color: var(--text-muted); }

/* The customer's orders in progress, on the cart page: approval and payment. */
.xd-cartside { display: grid; gap: 20px; align-content: start; min-width: 0; }
.xd-cartorders-host { margin: 0 0 20px; }
.xd-cartside > .xd-cartorders-host { margin: 0; }
.xd-cartorders-host:empty { display: none; }
/* The order just placed, beside the orders in progress (one column on phones). */
.xd-cartpair { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; align-items: start; margin: 0 0 24px; }
.xd-cartpair > .xd-placed, .xd-cartpair > .xd-cartorders-host { margin: 0; min-width: 0; }
/* The details form sits under the basket's subtotal. */
.xd-form--under-total { margin-top: 20px; }
.xd-cartorders {
  display: grid;
  gap: 12px;
  padding: 16px 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface, transparent);
}
.xd-cartorders__title { margin: 0; font-size: 17px; }

/* Where you are in a list, and the way out of it. */
.xd-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 12px;
  margin: 12px 0 0;
  font-size: 13px;
}
.xd-pager__at { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.xd-pager__nav { display: flex; gap: 14px; }
.xd-pager .xd-linkbtn[disabled] { opacity: 0.4; cursor: default; }

/* What was bought, above the money it came to. */
.xd-order__items {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 7px;
}
.xd-order__item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 14px;
}
.xd-order__itemname { display: grid; gap: 2px; }
.xd-order__qty { font-weight: 700; font-variant-numeric: tabular-nums; }
.xd-order__each,
.xd-order__notes { font-size: 12px; color: var(--text-muted); }
.xd-order__itemprice { font-variant-numeric: tabular-nums; white-space: nowrap; }

.xd-order__money {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 3px 12px;
  font-size: 14px;
}
.xd-order__money > span:nth-child(even) { text-align: right; }
.xd-order__money .is-total { padding-top: 6px; border-top: 1px solid var(--border); font-weight: 700; }

.xd-proof {
  display: grid;
  gap: 6px;
  padding: 11px;
  border: 1px dashed var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.xd-proof__label { font-size: 13px; font-weight: 600; }
.xd-proof input { font: inherit; font-size: 13px; }

/* ---------------------------------------------------------------- gallery --
 * A product photo that changes, for shops allowed more than one.
 *
 * The <img> keeps whichever class its design gave it and is sized entirely by
 * that class — this wrapper only provides something for the dots to sit in,
 * and a fade so the swap is not a jolt. Nothing here sets a width, a height
 * or an aspect ratio, so a design's own product-image rules still decide how
 * big the picture is.
 */
.xd-gal {
  position: relative;
  display: block;
}

.xd-gal img {
  display: block;
  width: 100%;
}

/* The next photo, laid exactly over the current one while it fades in
   (runtime.js crossfade). It keeps the design's own image class, so the
   corners and cropping match; only its place and opacity are set here. */
.xd-fade-next {
  position: absolute !important;
  margin: 0 !important;
  max-width: none !important;
  opacity: 0;
  pointer-events: none;
  object-fit: cover;
}

.xd-gal__dots {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 8px;
  display: flex;
  gap: 5px;
  justify-content: center;
  pointer-events: none;
}

.xd-gal__dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  /* Over an unknown photo, so each dot carries its own dark halo rather than
     trusting the picture behind it to be light. */
  background: rgba(255, 255, 255, 0.55);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35);
  transition: background 200ms ease, transform 200ms ease;
}

.xd-gal__dot.is-on {
  background: #fff;
  transform: scale(1.35);
}

@media (prefers-reduced-motion: reduce) {
  .xd-gal img,
  .xd-fade-next,
  .xd-gal__dot { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════
   Choosing a variant
   ═══════════════════════════════════════════════════════════════════

   The picker the runtime inserts above a product's add-to-order button —
   the colours, models or menu items a product comes in, and the sizes or
   meal options inside whichever is chosen.

   It is styled here rather than per design for the same reason it is built
   here: a provider picking a look is not picking whether they can sell a
   shirt in two colours. Everything is drawn from the theme tokens, so it
   takes on the provider's brand colour and radius without any design
   having to know it exists. The one thing it insists on is a full line of
   its own — it is inserted next to a button that may sit in a flex row,
   and a swatch strip squeezed beside a button is unreadable.
 */
/* A variant's own description, where the product had none to replace. */
.xd-variant-desc { margin: 0 0 12px; color: var(--text); line-height: 1.55; }
.xd-info-slot:empty { display: none; }

.xd-variants {
  width: 100%;
  flex-basis: 100%;
  margin: 0 0 18px;
  text-align: left;
}

.xd-variants__title {
  margin: 0 0 8px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted);
}

.xd-variants__title + .xd-variants__row { margin-bottom: 16px; }

.xd-variants__row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.xd-variant,
.xd-option {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-size: 14px;
  line-height: 1.3;
  cursor: pointer;
  transition: border-color 160ms ease, box-shadow 160ms ease;
}

.xd-variant { padding: 6px 12px; }

.xd-variant:hover,
.xd-option:hover { border-color: var(--brand); }

/* The chosen one is named as well as outlined: a ring alone is a colour
   difference, and that is not something every visitor can see. */
.xd-variant.is-on,
.xd-option.is-on {
  border-color: var(--brand);
  box-shadow: inset 0 0 0 1px var(--brand);
  font-weight: 600;
}

.xd-variant:focus-visible,
.xd-option:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

.xd-variant__img {
  width: 40px;
  height: 40px;
  border-radius: calc(var(--radius-sm) - 3px);
  object-fit: cover;
  flex: none;
}

.xd-variant__name { white-space: nowrap; }

.xd-option__price { color: var(--text-muted); }
.xd-option.is-on .xd-option__price { color: inherit; }

@media (prefers-reduced-motion: reduce) {
  .xd-variant,
  .xd-option { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════
   Moving between pages
   ═══════════════════════════════════════════════════════════════════

   A product's photograph travels from the catalogue into its own page
   instead of the two pages fading over each other. The runtime puts a
   `view-transition-name` on both copies of the picture for the length of
   the navigation; everything here is the timing.

   It belongs to the runtime rather than to any design, so every design has
   it and none of them can get it wrong — the same reason the basket and the
   account panel live there.

   A browser without View Transitions ignores all of this and the page
   changes as it always did. Nothing depends on the animation happening.
   ------------------------------------------------------------------ */

@media (prefers-reduced-motion: no-preference) {
  /* The page beneath crossfades quickly — long enough to read as a change,
     short enough not to be a wait. */
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 220ms;
  }

  /* The photograph itself moves and resizes. Slower than the crossfade,
     because this is the thing worth watching, and eased so it settles
     rather than stopping dead. */
  ::view-transition-group(xd-morph) {
    animation-duration: 420ms;
    animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
  }

  /* The two copies of the photo hold full opacity through the move. Left to
     the default they crossfade into each other mid-flight, which looks like
     a glitch rather than one picture travelling. */
  ::view-transition-old(xd-morph),
  ::view-transition-new(xd-morph) {
    animation: none;
    mix-blend-mode: normal;
    height: 100%;
  }
}

/*
 * Someone who asked for less motion gets none. The runtime skips the
 * transition entirely for them, so this is belt and braces for a browser
 * that runs one anyway.
 */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════
   The backdrop layer
   ═══════════════════════════════════════════════════════════════════

   A design can name a background animation in its template.json — see
   backdrops.js. The canvas is fixed behind everything and never takes a
   click.

   It sits BETWEEN the page's background colour and its content, so it shows
   wherever the page lets it through: margins, gutters, translucent panels.
   A design whose sections are all opaque will hide most of it, which is the
   right default — the backdrop is the room, not the furniture.
   ------------------------------------------------------------------ */

.xd-backdrop {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  /* Painted, never read. It carries no information. */
  user-select: none;
}

/* Content above the layer. Without this the canvas would cover the page
   rather than sit behind it. */
body > main,
body > #app {
  position: relative;
  z-index: 1;
}

/* ═══════════════════════════════════════════════════════════════════
   Product information (pack label)
   ═══════════════════════════════════════════════════════════════════

   Ingredients, nutritional values, allergens and storage, from
   h.productInfo(product). Every design drops the same markup into its
   product page, so this takes its colours and type from wherever it lands
   (currentColor, inherited font) and only sets spacing and the table.
*/
.xd-info {
  display: grid;
  gap: 14px;
  margin: 20px 0;
  text-align: left;
}

.xd-info__block {
  padding: 14px 16px;
  border: 1px solid color-mix(in srgb, currentColor 14%, transparent);
  border-radius: 12px;
  background: color-mix(in srgb, currentColor 4%, transparent);
}

.xd-info__title {
  margin: 0 0 8px;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.3;
}

.xd-info__block p {
  margin: 0 0 6px;
  font-size: 0.92rem;
  line-height: 1.55;
  overflow-wrap: anywhere;
}

.xd-info__block p:last-child { margin-bottom: 0; }

.xd-info__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}

.xd-info__table th,
.xd-info__table td {
  padding: 7px 0;
  border-bottom: 1px solid color-mix(in srgb, currentColor 10%, transparent);
  vertical-align: baseline;
}

.xd-info__table tr:last-child th,
.xd-info__table tr:last-child td { border-bottom: 0; }

.xd-info__table th {
  font-weight: 600;
  text-align: left;
  padding-right: 12px;
}

.xd-info__table td {
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.xd-info__table tr.is-sub th {
  padding-left: 16px;
  font-weight: 400;
  font-style: italic;
  opacity: 0.8;
}

.xd-info__table tr.is-caption th {
  font-weight: 400;
  font-size: 0.82rem;
  opacity: 0.7;
}

/* ═══════════════════════════════════════════════════════════════════
   Language switch
   ═══════════════════════════════════════════════════════════════════

   h.langSwitch(): "EN | FR" beside a design's sign-in button. It sits in
   eight different headers, so it borrows their colour and font and only
   draws a quiet pill with the current language filled in.
*/
.xd-lang {
  display: inline-flex;
  align-items: center;
  flex: none;
  gap: 2px;
  padding: 2px;
  border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
  border-radius: 999px;
  vertical-align: middle;
  line-height: 1;
}

.xd-lang__opt {
  min-width: 30px;
  min-height: 26px;
  padding: 4px 7px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  opacity: 0.65;
  cursor: pointer;
}

.xd-lang__opt:hover { opacity: 1; }

.xd-lang__opt[aria-pressed="true"] {
  background: color-mix(in srgb, currentColor 14%, transparent);
  opacity: 1;
}

.xd-lang__opt:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 1px;
}

/* ═══════════════════════════════════════════════════════════════════
   Paying with Blink (account panel, blink-pay.js)
   ═══════════════════════════════════════════════════════════════════ */
.xd-blink-offer { display: grid; }
.xd-pay__opt--blink { border-color: color-mix(in srgb, #e11d48 45%, var(--border)); }
.xd-pay__opt--blink:hover { border-color: #e11d48; }

.xd-blink {
  display: grid;
  gap: 8px;
  justify-items: center;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  text-align: center;
}
.xd-blink--done { border-color: #16a34a; }
.xd-blink__head { margin: 0; font-size: 15px; font-weight: 700; }
.xd-blink {
  /* Above any backdrop, gradient or scroll-reveal a design puts over its content. */
  position: relative;
  z-index: 2;
  isolation: isolate;
}
.xd-blink__qr {
  width: min(240px, 100%);
  aspect-ratio: 1;
  padding: 10px;
  border-radius: 10px;
  /* A QR is read dark-on-white whatever the site's colours are: always fully solid,
     never faded, masked, filtered or blended into the page behind it. */
  background: #fff !important;
  opacity: 1 !important;
  filter: none !important;
  -webkit-mask: none !important;
  mask: none !important;
  mix-blend-mode: normal !important;
  backdrop-filter: none !important;
  animation: none !important;
  transition: none !important;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.12);
}
.xd-blink__qr svg {
  display: block;
  width: 100%;
  height: 100%;
  opacity: 1 !important;
  filter: none !important;
  mix-blend-mode: normal !important;
  shape-rendering: crispEdges;
}
.xd-blink__clock { margin: 0; font-size: 13px; color: var(--text-muted); }
.xd-blink__clock strong { color: var(--text); font-variant-numeric: tabular-nums; }

/* The order just placed: the X Delivery logo while it is confirmed, a check when approved. */
.xd-placed { text-align: center; display: grid; justify-items: center; gap: 4px; }
.xd-placed__logo {
  position: relative;
  display: grid;
  place-items: center;
  width: 76px;
  height: 76px;
  margin-bottom: 6px;
}
.xd-placed__logo::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 3px solid color-mix(in srgb, var(--brand, #1d4ed8) 18%, transparent);
  border-top-color: var(--brand, #1d4ed8);
  animation: xd-spin 0.9s linear infinite;
}
.xd-placed__logo.is-still::before { animation-duration: 2.4s; }
.xd-placed__logo img { width: 44px; height: 44px; object-fit: contain; border-radius: 8px; }
.xd-placed__check { width: 76px; height: 76px; margin-bottom: 6px; }
.xd-placed__check svg { width: 100%; height: 100%; fill: none; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.xd-placed__check circle {
  stroke: #16a34a;
  stroke-dasharray: 151;
  stroke-dashoffset: 151;
  animation: xd-draw 0.5s ease-out forwards;
}
.xd-placed__check path {
  stroke: #16a34a;
  stroke-dasharray: 40;
  stroke-dashoffset: 40;
  animation: xd-draw 0.35s 0.45s ease-out forwards;
}
@keyframes xd-spin { to { transform: rotate(360deg); } }
@keyframes xd-draw { to { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) {
  .xd-placed__logo::before { animation: none; }
  .xd-placed__check circle, .xd-placed__check path { animation: none; stroke-dashoffset: 0; }
}

.xd-linkbtn--danger { color: #dc2626; }
