/* The order portal a reseller's buyer opens.

   Loaded by two pages: the builder's live preview, and the portal page itself. They
   share this file so a setting cannot mean one thing in the preview and another on
   the real page.

   It is deliberately self-contained. The portal is served on a domain of its own,
   where nothing about the shop supplying it may be visible — so this file names no
   other stylesheet, carries no house style, and defines the few tokens it needs
   rather than inheriting them. Everything else comes from the --sp-* variables the
   reseller's saved theme sets at runtime. */

:root {
  /* The only value either block borrows from elsewhere. A page that also loads the
     site stylesheet has it overwritten with the same colour, which is harmless. */
  --line-5: rgba(255,255,255,.14);
}

/* The builder's preview sits on a page that already sets border-box; lobby.html loads
   nothing but this file and so fell back to content-box, which quietly made the same
   rule produce different sizes in the two places. Settled here instead of assumed. */
.shop-preview, .shop-preview *, .shop-preview *::before, .shop-preview *::after { box-sizing: border-box; }

/* The portal itself. Every option maps to one data-* attribute or CSS variable, so the
   saved theme is applied by setting values, never by swapping stylesheets. */
.shop-preview {
  --sp-bg: #0D0F14; --sp-surface: #161922; --sp-line: rgba(255,255,255,.09); --sp-fg: #F1F3F7; --sp-muted: #8B91A0;
  --sp-r: 10px; --sp-scale: 1; --sp-dot: 16px; --sp-pad: 12px 13px; --sp-gap: 8px; --sp-head-w: 700; --sp-glow: .55;
  --sp-font-head: 'Inter', system-ui, sans-serif; --sp-font-body: 'Inter', system-ui, sans-serif;
  position: relative; overflow: hidden; border-radius: 16px; border: 1px solid var(--line-5);
  background-color: var(--sp-bg); color: var(--sp-fg); font-family: var(--sp-font-body);
  box-shadow: 0 30px 70px -40px rgba(0,0,0,.8);
}
.shop-preview[data-mode="light"] { --sp-bg: #F7F8FB; --sp-surface: #FFFFFF; --sp-line: rgba(15,23,42,.08); --sp-fg: #0B1221; --sp-muted: #697586; }
/* White on near-white needs a shadow to read as a surface; a darker border would
   just make it look boxed in. */
.shop-preview[data-mode="light"] .sp-card { box-shadow: 0 1px 2px rgba(15,23,42,.05), 0 1px 1px rgba(15,23,42,.03); }
.shop-preview[data-mode="light"][data-cards="flat"] .sp-card { box-shadow: none; }
.shop-preview[data-corners="sharp"] { --sp-r: 2px; }
.shop-preview[data-corners="round"] { --sp-r: 14px; }
.shop-preview[data-size="s"] { --sp-scale: .92; }
.shop-preview[data-size="l"] { --sp-scale: 1.08; }
.shop-preview[data-spacing="compact"] { --sp-pad: 9px 10px; --sp-gap: 6px; }
.shop-preview[data-spacing="spacious"] { --sp-pad: 16px 16px; --sp-gap: 12px; }
.shop-preview[data-weight="600"] { --sp-head-w: 600; }
.shop-preview[data-weight="800"] { --sp-head-w: 800; }
/* backgrounds */
.shop-preview[data-bg="glow"] { background-image: radial-gradient(120% 70% at 90% -10%, color-mix(in srgb, var(--sp-accent) calc(var(--sp-glow) * 40%), transparent), transparent 62%); }
.shop-preview[data-bg="gradient"] { background-image: linear-gradient(150deg, color-mix(in srgb, var(--sp-accent) calc(var(--sp-glow) * 34%), transparent), transparent 55%, color-mix(in srgb, var(--sp-accent2) calc(var(--sp-glow) * 34%), transparent)); }
.shop-preview[data-bg="dots"] { background-image: radial-gradient(circle, color-mix(in srgb, var(--sp-line) 70%, transparent) 1px, transparent 1.3px); background-size: 15px 15px; }
.shop-preview[data-bg="grid"] { background-image: radial-gradient(120% 80% at 50% -10%, color-mix(in srgb, var(--sp-accent) calc(var(--sp-glow) * 26%), transparent), transparent 60%), linear-gradient(color-mix(in srgb, var(--sp-line) 55%, transparent) 1px, transparent 1px), linear-gradient(90deg, color-mix(in srgb, var(--sp-line) 55%, transparent) 1px, transparent 1px); background-size: auto, 26px 26px, 26px 26px; }
.shop-preview[data-bg="lines"] { background-image: repeating-linear-gradient(135deg, color-mix(in srgb, var(--sp-line) 55%, transparent) 0 1px, transparent 1px 11px); }
.shop-preview[data-bg="image"] { background-image: linear-gradient(color-mix(in srgb, var(--sp-bg) calc(var(--sp-glow) * 100%), transparent), color-mix(in srgb, var(--sp-bg) calc(var(--sp-glow) * 100%), transparent)), var(--sp-bgimg), radial-gradient(120% 70% at 90% -10%, color-mix(in srgb, var(--sp-accent) 25%, transparent), transparent 62%); background-size: cover; background-position: center; }

.sp-banner { display: none; padding: 7px 12px; text-align: center; font-size: calc(10.5px * var(--sp-scale)); font-weight: 700; background: linear-gradient(90deg, var(--sp-accent), var(--sp-accent2)); color: var(--sp-on-accent); }
.shop-preview[data-banner="on"] .sp-banner { display: block; }
.sp-inner { padding: 14px; }
.sp-bar { display: flex; align-items: center; justify-content: space-between; gap: 9px; padding-bottom: 12px; border-bottom: 1px solid var(--sp-line); min-height: 38px; }
.shop-preview[data-header="center"] .sp-bar { justify-content: center; position: relative; }
/* Centred means centred: a logo sitting beside the name still reads as a left-aligned
   lockup that happens to be in the middle. Stacked, it is a mark over a wordmark. */
.shop-preview[data-header="center"] .sp-brand { flex-direction: column; gap: 7px; text-align: center; }
.shop-preview[data-header="center"] .sp-meta { position: absolute; right: 0; top: 0; }
.sp-brand { display: flex; align-items: center; gap: 9px; min-width: 0; }
.sp-logo { width: 26px; height: 26px; border-radius: calc(var(--sp-r) * .6); overflow: hidden; flex-shrink: 0; display: flex; align-items: center; justify-content: center; background: var(--sp-accent); color: var(--sp-on-accent); font-family: var(--sp-font-head); font-weight: 800; font-size: 12px; }
.sp-logo img { width: 100%; height: 100%; object-fit: cover; }
.sp-logo img[hidden], .sp-name[hidden], .sp-pill[hidden], .sp-foot[hidden] { display: none; }
.sp-name { min-width: 0; font-family: var(--sp-font-head); font-weight: var(--sp-head-w); font-size: calc(13px * var(--sp-scale)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sp-pill { font-size: 10px; font-weight: 600; padding: 4px 9px; border-radius: 999px; border: 1px solid var(--sp-line); color: var(--sp-muted); }
/* The order reference, so a buyer with a problem has something to quote at the person
   who sold it to them. It is the same code the seller sees against the order, and it
   is already in the link, so showing it gives nothing away. A button, because the
   useful thing to do with it is copy it. */
.sp-meta { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.sp-meta[hidden] { display: none; }
button.sp-pill { background: none; font-family: var(--sp-font-body); line-height: 1.2; cursor: pointer; }
.sp-code { font-family: ui-monospace,'SF Mono',Menlo,monospace; letter-spacing: .03em; transition: color .2s ease, border-color .2s ease; }
button.sp-code:hover { color: var(--sp-fg); border-color: color-mix(in srgb, var(--sp-fg) 25%, var(--sp-line)); }
.sp-code.is-copied { color: var(--sp-accent); border-color: var(--sp-accent); }
.sp-hero { padding: 18px 2px 10px; }
.shop-preview[data-header="center"] .sp-hero { text-align: center; }

/* "Centered" has to mean the page, not just the masthead. A centred header sitting over
   left-aligned cards reads as something that went wrong rather than as a choice. */
.shop-preview[data-header="center"] .sp-card { text-align: center; }
.shop-preview[data-header="center"] .sp-row { justify-content: center; }
.shop-preview[data-header="center"] .sp-note,
.shop-preview[data-header="center"] .sp-err { text-align: center; }
/* The vertical progress lists keep their own geometry — the markers have to stay in a
   column and the timeline's connector is positioned against them — so the list is
   centred as a block instead of centring each row on its own. */
.shop-preview[data-header="center"][data-progress="numbers"] .sp-steps,
.shop-preview[data-header="center"][data-progress="checks"] .sp-steps,
.shop-preview[data-header="center"][data-progress="timeline"] .sp-steps,
.shop-preview[data-header="center"][data-progress="bare"] .sp-steps {
  width: max-content; max-width: 100%; margin-left: auto; margin-right: auto; text-align: left;
}
/* The consent line is too long to hold its own width, so it centres its text and the
   box rides alongside it rather than clinging to a ragged left edge. */
.shop-preview[data-header="center"] .sp-check { justify-content: center; align-items: center; text-align: center; }
/* The access block turns into a stack: label, then the value, then the button under it,
   all on the centre line. */
.shop-preview[data-header="center"] .sp-cred-row { flex-direction: column; gap: calc(7px * var(--sp-scale)); }
.shop-preview[data-header="center"] .sp-cred-v { flex: 0 0 auto; width: 100%; text-align: center; }
.shop-preview[data-header="center"] .sp-cred-copy { margin-left: auto; margin-right: auto; }
/* With everything centred the accent belongs along the top edge, not down one side. */
.shop-preview[data-header="center"] .sp-cred::before { inset: 0 0 auto 0; width: auto; height: 3px; }
.sp-kicker { font-family: var(--sp-font-head); font-size: calc(10px * var(--sp-scale)); font-weight: 600; color: var(--sp-accent); }
.sp-hud { margin-top: 4px; font-family: var(--sp-font-head); font-weight: var(--sp-head-w); font-size: calc(20px * var(--sp-scale)); line-height: 1.15; letter-spacing: -.01em; }
.sp-welcome { margin-top: 6px; font-size: calc(11px * var(--sp-scale)); line-height: 1.5; color: var(--sp-muted); }
.shop-preview[data-case="upper"] .sp-hud, .shop-preview[data-case="upper"] .sp-card-title { text-transform: uppercase; letter-spacing: .03em; }
.shop-preview[data-case="upper"] .sp-kicker { text-transform: uppercase; letter-spacing: .14em; }

.sp-state { display: none; }
.shop-preview[data-state="setup"] .sp-state[data-show="setup"],
.shop-preview[data-state="session"] .sp-state[data-show="session"],
.shop-preview[data-state="done"] .sp-state[data-show="done"] { display: block; }
/* Builder-only screens. The real page has one "session" screen whose contents change
   with the order's status; the builder splits that one screen into the three moments a
   reseller wants to look at separately — waiting for a host, the host's details landing,
   and the clock running — so every step can be checked before the portal goes out. */
.shop-preview[data-state="waiting"] .sp-state[data-show="waiting"],
.shop-preview[data-state="ready"] .sp-state[data-show="ready"] { display: block; }

/* cards */
.sp-card { border-radius: var(--sp-r); background: var(--sp-surface); border: 1px solid var(--sp-line); padding: var(--sp-pad); margin-top: var(--sp-gap); }
.shop-preview[data-cards="outline"] .sp-card { background: transparent; border-color: color-mix(in srgb, var(--sp-fg) 13%, transparent); }
.shop-preview[data-cards="glass"] .sp-card { background: color-mix(in srgb, var(--sp-surface) 50%, transparent); border-color: color-mix(in srgb, var(--sp-fg) 12%, transparent); box-shadow: 0 12px 30px -18px rgba(0,0,0,.6); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
.shop-preview[data-cards="flat"] .sp-card { background: transparent; border: none; border-radius: 0; border-top: 1px solid var(--sp-line); padding-left: 2px; padding-right: 2px; }
.sp-center { text-align: center; }
.sp-card-title { font-family: var(--sp-font-head); font-weight: var(--sp-head-w); font-size: calc(13px * var(--sp-scale)); }
.sp-muted { margin-top: 3px; font-size: calc(10.5px * var(--sp-scale)); line-height: 1.5; color: var(--sp-muted); }
.sp-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.sp-label { display: block; font-size: calc(9.5px * var(--sp-scale)); font-weight: 600; letter-spacing: .04em; color: var(--sp-muted); }
.sp-time { margin-top: 8px; font-family: var(--sp-font-head); font-weight: var(--sp-head-w); font-size: calc(25px * var(--sp-scale)); line-height: 1; letter-spacing: -.01em; font-variant-numeric: tabular-nums; }

/* status badge */
.sp-status { display: inline-flex; align-items: center; gap: 5px; font-family: var(--sp-font-head); font-size: calc(9.5px * var(--sp-scale)); font-weight: 700; padding: 3px 8px; border-radius: 999px; color: var(--sp-accent); background: color-mix(in srgb, var(--sp-accent) 14%, transparent); }
.sp-status i { width: 5px; height: 5px; border-radius: 50%; background: currentColor; }
.shop-preview[data-badge="dot"] .sp-status { background: none; padding: 0; }
.shop-preview[data-badge="square"] .sp-status { border-radius: 3px; }

/* progress bar + steps */
.sp-bar-track { height: 5px; margin-top: 10px; border-radius: 999px; background: var(--sp-line); overflow: hidden; }
.sp-bar-track span { position: relative; display: block; height: 100%; border-radius: inherit; overflow: hidden; background: var(--sp-accent); }
.shop-preview[data-btn="gradient"] .sp-bar-track span, .shop-preview[data-bg="gradient"] .sp-bar-track span { background: linear-gradient(90deg, var(--sp-accent), var(--sp-accent2)); }
.sp-steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.sp-steps li { position: relative; display: flex; align-items: center; gap: 9px; font-size: calc(10.5px * var(--sp-scale)); color: var(--sp-muted); }
.sp-steps i { position: relative; z-index: 1; width: var(--sp-dot); height: var(--sp-dot); border-radius: 50%; flex-shrink: 0; display: grid; place-items: center; font-style: normal; font-size: 8.5px; font-weight: 700; border: 1px solid var(--sp-line); background: var(--sp-surface); }
.sp-steps i::before { content: attr(data-n); }
.sp-steps li.is-done { color: var(--sp-fg); }
.sp-steps li.is-done i { border-color: transparent; background: color-mix(in srgb, var(--sp-accent) 18%, var(--sp-surface)); color: var(--sp-accent); }
.sp-steps li.is-now { color: var(--sp-fg); font-weight: 700; }
.sp-steps li.is-now i { border-color: transparent; background: var(--sp-accent); color: var(--sp-on-accent); }
.shop-preview[data-corners="sharp"] .sp-steps i { border-radius: 3px; }
.shop-preview[data-progress="checks"] .sp-steps li.is-done i::before { content: "\2713"; }
.shop-preview[data-progress="timeline"] .sp-steps { gap: 10px; }
.shop-preview[data-progress="timeline"] .sp-steps li:not(:last-child)::after { content: ""; position: absolute; left: calc(var(--sp-dot) / 2 - 1px); top: calc(var(--sp-dot) - 1px); height: 14px; width: 2px; border-radius: 2px; background: var(--sp-line); }
.shop-preview[data-progress="timeline"] .sp-steps li.is-done:not(:last-child)::after { background: var(--sp-accent); }
.shop-preview[data-progress="timeline"] .sp-steps i { font-size: 0; }
.shop-preview[data-progress="timeline"] .sp-steps li.is-done i::before { content: "\2713"; font-size: 8.5px; }
.shop-preview[data-progress="timeline"] .sp-steps li.is-now i { box-shadow: 0 0 0 3px color-mix(in srgb, var(--sp-accent) 25%, transparent); }

/* These three used to be welded to a layout — the dot row came with "hero", the rail
   with "split", the unfilled markers with "minimal" — so picking a look meant taking a
   progress style with it. They are plain options now, usable under any layout. */

/* Dots: a centred row, with only the step you are on named underneath. */
.shop-preview[data-progress="dots"] .sp-steps { position: relative; flex-direction: row; justify-content: center; gap: 6px; padding-bottom: calc(var(--sp-dot) + 2px); }
.shop-preview[data-progress="dots"] .sp-steps li { position: static; }
.shop-preview[data-progress="dots"] .sp-steps li span { display: none; }
.shop-preview[data-progress="dots"] .sp-steps li.is-now span { display: block; position: absolute; left: 0; right: 0; bottom: 0; text-align: center; font-size: calc(9.5px * var(--sp-scale)); }

/* Rail: the same row, joined up, so progress reads as distance covered. */
.shop-preview[data-progress="rail"] .sp-steps { flex-direction: row; gap: 0; margin-top: 6px; }
.shop-preview[data-progress="rail"] .sp-steps li { position: relative; flex: 1; flex-direction: column; align-items: center; gap: 5px; padding-bottom: calc(var(--sp-dot) - 2px); }
.shop-preview[data-progress="rail"] .sp-steps li span { position: absolute; top: calc(var(--sp-dot) + 6px); left: 50%; translate: -50% 0; font-size: calc(8.5px * var(--sp-scale)); white-space: nowrap; opacity: 0; }
.shop-preview[data-progress="rail"] .sp-steps li.is-now span { opacity: 1; }
.shop-preview[data-progress="rail"] .sp-steps li:not(:last-child)::after { content: ""; position: absolute; left: calc(50% + var(--sp-dot) / 2 + 3px); right: calc(-50% + var(--sp-dot) / 2 + 3px); top: calc(var(--sp-dot) / 2 - 1px); height: 2px; background: var(--sp-line); }
.shop-preview[data-progress="rail"] .sp-steps li.is-done:not(:last-child)::after { background: var(--sp-accent); }

/* Bare: the markers lose their fill and keep only their colour. */
.shop-preview[data-progress="bare"] .sp-steps i { background: none; border-color: transparent; color: var(--sp-muted); }
.shop-preview[data-progress="bare"] .sp-steps li.is-done i { background: none; color: var(--sp-accent); }
.shop-preview[data-progress="bare"] .sp-steps li.is-done i::before { content: "\2713"; }
.shop-preview[data-progress="bare"] .sp-steps li.is-now i { background: none; color: var(--sp-accent); box-shadow: none; }

/* setup + complete bits */
.sp-input { margin-top: 10px; padding: 8px 10px; border-radius: calc(var(--sp-r) * .8); border: 1px solid var(--sp-line); background: color-mix(in srgb, var(--sp-bg) 60%, transparent); font-family: ui-monospace,'SF Mono',Menlo,monospace; font-size: 11px; color: var(--sp-muted); }
.sp-check { display: flex; align-items: flex-start; gap: 8px; margin-top: 10px; font-size: calc(10px * var(--sp-scale)); line-height: 1.45; color: var(--sp-muted); cursor: pointer; }
.sp-check input {
  appearance: none; -webkit-appearance: none; width: 14px; height: 14px; margin: 1px 0 0; flex-shrink: 0; cursor: pointer;
  border-radius: 4px; border: 1px solid var(--sp-line); background: color-mix(in srgb, var(--sp-bg) 60%, transparent);
  display: grid; place-content: center; transition: background .2s ease, border-color .2s ease;
}
.sp-check input:checked { background: var(--sp-accent); border-color: var(--sp-accent); }
.sp-check input:checked::after { content: ""; width: 7px; height: 4px; border-left: 2px solid var(--sp-on-accent); border-bottom: 2px solid var(--sp-on-accent); transform: translateY(-1px) rotate(-45deg); }
.shop-preview[data-corners="sharp"] .sp-check input { border-radius: 2px; }
.sp-done { display: inline-grid; place-items: center; width: 34px; height: 34px; margin-bottom: 8px; border-radius: 50%; background: color-mix(in srgb, var(--sp-accent) 16%, transparent); color: var(--sp-accent); font-weight: 800; }

/* buttons */
button.sp-btn { width: 100%; cursor: pointer; }
button.sp-btn:disabled { opacity: .45; cursor: not-allowed; }
.sp-btn { display: block; margin-top: 12px; padding: 9px 0; text-align: center; border-radius: calc(var(--sp-r) * .8); font-family: var(--sp-font-head); font-size: calc(11px * var(--sp-scale)); font-weight: 700; background: var(--sp-accent); color: var(--sp-on-accent); border: 1px solid var(--sp-accent); }
.shop-preview[data-btn="gradient"] .sp-btn { background: linear-gradient(120deg, var(--sp-accent), var(--sp-accent2)); border-color: transparent; }
.shop-preview[data-btn="soft"] .sp-btn { background: color-mix(in srgb, var(--sp-accent) 16%, transparent); color: var(--sp-accent); border-color: transparent; }
.shop-preview[data-btn="outline"] .sp-btn { background: transparent; color: var(--sp-accent); }
.shop-preview[data-btnshape="square"] .sp-btn { border-radius: 2px; }
.shop-preview[data-btnshape="pill"] .sp-btn { border-radius: 999px; }
.sp-btn.is-secondary, .shop-preview[data-btn] .sp-btn.is-secondary { background: transparent; color: var(--sp-fg); border: 1px solid var(--sp-line); margin-top: var(--sp-gap); }

/* footer */
.sp-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--sp-line); font-size: calc(9.5px * var(--sp-scale)); color: var(--sp-muted); }
.shop-preview[data-header="center"] .sp-foot { flex-direction: column; justify-content: center; }
.sp-socials { display: flex; gap: 6px; }
.sp-social { width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; border: 1px solid var(--sp-line); color: var(--sp-fg); }
.sp-social svg { width: 12px; height: 12px; }

/* ---- Compositions: each one rearranges the portal, not just its colours ---- */
.sp-ring { display: none; position: relative; width: 150px; height: 150px; margin: 12px auto 4px; }
.sp-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.sp-ring circle { fill: none; stroke-width: 7; }
.sp-ring-bg { stroke: var(--sp-line); }
.sp-ring-fg { stroke: var(--sp-accent); stroke-linecap: round; stroke-dasharray: 327; stroke-dashoffset: 209; }
.sp-ring-mid { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; }
.sp-ring-mid b { font-family: var(--sp-font-head); font-weight: var(--sp-head-w); font-size: calc(21px * var(--sp-scale)); letter-spacing: -.01em; font-variant-numeric: tabular-nums; }
.sp-ring-mid small { font-size: calc(9.5px * var(--sp-scale)); color: var(--sp-muted); }

/* Hero: the timer is the page; everything else is quiet underneath. */
.shop-preview[data-layout="hero"] .sp-ring { display: block; }
/* Hero used to hide the countdown, which left the buyer with no idea how long they
   had. It is the one number on the page they came for — so hero now means it is
   bigger and centred, not absent. */
.shop-preview[data-layout="hero"] .sp-order-card { text-align: center; padding-top: 16px; }
.shop-preview[data-layout="hero"] .sp-order-card .sp-row { justify-content: center; gap: 8px; }
.shop-preview[data-layout="hero"] .sp-time { font-size: calc(31px * var(--sp-scale)); margin-top: 10px; }
.shop-preview[data-layout="hero"] .sp-bar-track { height: 3px; margin-top: 12px; }
.shop-preview[data-layout="hero"] .sp-hero { padding-bottom: 4px; }
.shop-preview[data-layout="hero"] .sp-steps + *, .shop-preview[data-layout="hero"] .sp-label { text-align: center; }

/* Split: order facts beside the clock, steps run left to right. */
.shop-preview[data-layout="split"] .sp-order-card { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 4px 14px; }
.shop-preview[data-layout="split"] .sp-order-card .sp-row { grid-column: 1; flex-direction: column; align-items: flex-start; gap: 6px; }
.shop-preview[data-layout="split"] .sp-time { grid-column: 2; grid-row: 1 / span 2; margin: 0; }
.shop-preview[data-layout="split"] .sp-order-card .sp-muted { grid-column: 1 / -1; }
.shop-preview[data-layout="split"] .sp-bar-track { grid-column: 1 / -1; }

/* Ticket: a pass with perforated edges and label/value rows. */
.shop-preview[data-layout="ticket"] .sp-card { position: relative; border-style: dashed; }
.shop-preview[data-layout="ticket"] .sp-order-card::before, .shop-preview[data-layout="ticket"] .sp-order-card::after {
  content: ""; position: absolute; bottom: -9px; width: 16px; height: 16px; border-radius: 50%; background: var(--sp-bg); border: 1px dashed var(--sp-line);
}
.shop-preview[data-layout="ticket"] .sp-order-card::before { left: -9px; clip-path: inset(0 0 50% 50%); }
.shop-preview[data-layout="ticket"] .sp-order-card::after { right: -9px; clip-path: inset(0 50% 50% 0); }
.shop-preview[data-layout="ticket"] .sp-order-card { padding-bottom: 16px; }
.shop-preview[data-layout="ticket"] .sp-label { font-family: ui-monospace,'SF Mono',Menlo,monospace; }
.shop-preview[data-layout="ticket"] .sp-time { letter-spacing: .04em; }
.shop-preview[data-layout="ticket"] .sp-hero { text-align: center; }
.shop-preview[data-layout="ticket"] .sp-hud { letter-spacing: .04em; }
.shop-preview[data-layout="ticket"] .sp-status { border-radius: 3px; font-family: ui-monospace,'SF Mono',Menlo,monospace; letter-spacing: .04em; }

/* Console: a terminal read-out. */
.shop-preview[data-layout="console"] .sp-hud { letter-spacing: .02em; }
.shop-preview[data-layout="console"] .sp-kicker::before { content: "// "; }
.shop-preview[data-layout="console"] .sp-card { border-style: solid; }
.shop-preview[data-layout="console"] .sp-status { border-radius: 2px; background: none; box-shadow: inset 0 0 0 1px currentColor; }
.shop-preview[data-layout="console"] .sp-status::before { content: "["; margin-right: 1px; }
.shop-preview[data-layout="console"] .sp-status::after { content: "]"; margin-left: 1px; }
.shop-preview[data-layout="console"] .sp-status i { display: none; }
.shop-preview[data-layout="console"] .sp-steps li { gap: 7px; }
.shop-preview[data-layout="console"] .sp-steps i { display: none; }
.shop-preview[data-layout="console"] .sp-steps li::before { content: "[ ]"; color: var(--sp-muted); }
.shop-preview[data-layout="console"] .sp-steps li.is-done::before { content: "[x]"; color: var(--sp-accent); }
.shop-preview[data-layout="console"] .sp-steps li.is-now::before { content: ">>"; color: var(--sp-accent); }
.shop-preview[data-layout="console"] .sp-steps li.is-now span::after { content: "_"; margin-left: 4px; }
.shop-preview[data-layout="console"] .sp-btn { letter-spacing: .06em; }

/* Minimal: no card chrome at all, just type and hairlines. */
.shop-preview[data-layout="minimal"] .sp-card { background: none !important; border: none; border-top: 1px solid var(--sp-line); border-radius: 0; padding: 14px 2px; backdrop-filter: none; box-shadow: none; }
.shop-preview[data-layout="minimal"] .sp-order-card { border-top: none; padding-top: 6px; }
.shop-preview[data-layout="minimal"] .sp-status { background: none; padding: 0; }
.shop-preview[data-layout="minimal"] .sp-bar-track { height: 2px; }
.shop-preview[data-layout="minimal"] .sp-hud { font-size: calc(24px * var(--sp-scale)); }
.shop-preview[data-layout="minimal"] .sp-time { font-size: calc(30px * var(--sp-scale)); }
.shop-preview[data-layout="minimal"] .sp-btn { background: none !important; border: none; border-top: 1px solid var(--sp-line); border-radius: 0; color: var(--sp-accent); padding: 12px 0 2px; }
.shop-preview[data-layout="minimal"] .sp-bar { border-bottom: none; }

/* animations */
@keyframes spPulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@keyframes spShimmer { from { translate: -100% 0; } to { translate: 250% 0; } }
.shop-preview[data-anim="on"] .sp-status i { animation: spPulse 1.6s ease-in-out infinite; }
.shop-preview[data-anim="on"] .sp-bar-track span::after { content: ""; position: absolute; inset: 0; width: 40%; background: linear-gradient(90deg, transparent, rgba(255,255,255,.45), transparent); animation: spShimmer 2.2s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .shop-preview .sp-status i, .shop-preview .sp-bar-track span::after { animation: none; } }

/* ---------- the reseller's portal, as the buyer actually sees it ----------
   lobby.html renders the same markup as the builder's preview, so every setting means
   the same thing in both. The only differences are the ones that have to be: no card
   frame, bigger type, and room to breathe on a phone. */
/* The card used to sit inside a wrapper carrying its own hard-coded max-width. The two
   numbers drifted apart the moment the card was resized, and the card then sat against
   the left edge of a wider box — centred wrapper, off-centre card. One source for the
   width now, and the card centres itself regardless. */
.sp-shell { width: 100%; max-width: 460px; }
.shop-preview.sp-live { margin-left: auto; margin-right: auto; }

.sp-page { margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: clamp(16px, 4vw, 40px) 16px; background: var(--sp-page-bg, #0D0F14); }
.shop-preview.sp-live {
  /* 1.55 at 560px wide made the card fill a desktop window like a billboard. This is a
     checkout page: it should read as one focused card, not as the whole screen. */
  --sp-scale: 1.3; --sp-dot: 20px;
  width: 100%; max-width: 460px; border-radius: 18px;
  box-shadow: 0 40px 110px -50px rgba(0,0,0,.9);
}
.shop-preview.sp-live .sp-inner { padding: clamp(16px, 3.4vw, 26px); }
.shop-preview.sp-live .sp-logo { width: 34px; height: 34px; font-size: 15px; }
.shop-preview.sp-live .sp-banner { padding: 9px 14px; }
.shop-preview.sp-live .sp-hero { padding: 20px 2px 10px; }
.shop-preview.sp-live .sp-steps i { font-size: 10px; }

/* A real field and a real button, wearing the preview's clothes. */
.sp-live .sp-field {
  width: 100%; margin-top: 10px; padding: 11px 13px; border-radius: calc(var(--sp-r) * .8);
  border: 1px solid var(--sp-line); background: color-mix(in srgb, var(--sp-bg) 60%, transparent);
  font-family: ui-monospace,'SF Mono',Menlo,monospace; font-size: 13px; color: var(--sp-fg);
  transition: border-color .2s ease;
}
.sp-live .sp-field::placeholder { color: var(--sp-muted); }
.sp-live .sp-field:focus { outline: none; border-color: var(--sp-accent); }
.sp-live .sp-field[aria-invalid="true"] { border-color: #F87171; }
.sp-live .sp-plats { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 10px; }
.shop-preview[data-header="center"] .sp-plats,
.shop-preview[data-header="center"] .sp-plats-demo { justify-content: center; }
.shop-preview[data-header="center"] .sp-field,
.shop-preview[data-header="center"] .sp-input { text-align: center; }
.sp-live .sp-plat {
  padding: 7px 12px; border-radius: 999px; border: 1px solid var(--sp-line); cursor: pointer;
  background: transparent; color: var(--sp-muted); font-family: var(--sp-font-body);
  font-size: calc(10.5px * var(--sp-scale) * .78); font-weight: 600; transition: all .2s ease;
}
.sp-live .sp-plat:hover { border-color: color-mix(in srgb, var(--sp-accent) 50%, var(--sp-line)); color: var(--sp-fg); }
.sp-live .sp-plat.is-active { border-color: var(--sp-accent); background: color-mix(in srgb, var(--sp-accent) 15%, transparent); color: var(--sp-accent); }
.sp-live button.sp-btn { cursor: pointer; font-family: var(--sp-font-head); }
.sp-live button.sp-btn[disabled] { opacity: .45; cursor: not-allowed; }
.sp-live .sp-err { margin-top: 8px; font-size: 12.5px; line-height: 1.5; color: #F87171; }
.sp-note { margin-top: 10px; font-size: calc(10.5px * var(--sp-scale) * .82); line-height: 1.55; color: var(--sp-muted); }

/* The rules for the product that was bought. They are not decoration: breaking one is
   what gets a buyer banned or refused a refund, so they are set as a list that has to
   be read, not as a muted footnote. Unprefixed, so the builder's preview carries them. */
.sp-rules { display: flex; flex-direction: column; gap: calc(5px * var(--sp-scale)); margin-top: calc(8px * var(--sp-scale)); }
.sp-rules[hidden] { display: none; }
.sp-rule {
  display: flex; align-items: flex-start; gap: calc(7px * var(--sp-scale));
  font-size: calc(10px * var(--sp-scale)); line-height: 1.5; color: var(--sp-fg);
}
.sp-rule::before {
  content: ""; flex-shrink: 0; width: calc(4px * var(--sp-scale)); height: calc(4px * var(--sp-scale));
  margin-top: calc(6px * var(--sp-scale)); border-radius: 50%; background: var(--sp-accent);
}
.shop-preview[data-header="center"] .sp-rules,
.shop-preview[data-header="center"] .sp-rules-body { align-items: center; }
.shop-preview[data-header="center"] .sp-rule { text-align: left; }

/* ---------- the rules block ----------
   Collapsible, because during a session it is reference rather than reading, and open
   to begin with so it is read at least once. */
.sp-rules-card { padding-top: calc(9px * var(--sp-scale)); padding-bottom: calc(9px * var(--sp-scale)); }
.sp-rules-toggle {
  display: flex; align-items: center; gap: calc(8px * var(--sp-scale)); width: 100%;
  padding: 0; border: 0; background: none; cursor: pointer; color: var(--sp-fg);
  font-family: var(--sp-font-body); text-align: left;
}
.sp-rules-mark {
  display: grid; place-items: center; flex-shrink: 0;
  width: calc(17px * var(--sp-scale)); height: calc(17px * var(--sp-scale));
  border-radius: calc(var(--sp-r) * .5);
  background: color-mix(in srgb, var(--sp-accent) 18%, transparent); color: var(--sp-accent);
}
.sp-rules-mark svg { width: 65%; height: 65%; }
.sp-rules-title {
  flex: 1; min-width: 0; font-family: var(--sp-font-head); font-weight: 700;
  font-size: calc(10.5px * var(--sp-scale)); letter-spacing: .03em;
}
.sp-rules-count {
  flex-shrink: 0; padding: 1px calc(6px * var(--sp-scale)); border-radius: 999px;
  background: color-mix(in srgb, var(--sp-accent) 16%, transparent); color: var(--sp-accent);
  font-size: calc(8.5px * var(--sp-scale)); font-weight: 700; font-variant-numeric: tabular-nums;
}
.sp-rules-chev { flex-shrink: 0; width: calc(11px * var(--sp-scale)); height: calc(11px * var(--sp-scale)); color: var(--sp-muted); transition: rotate .25s ease; }
.sp-rules-card.is-shut .sp-rules-chev { rotate: -90deg; }

.sp-rules-body {
  display: flex; flex-direction: column; gap: calc(5px * var(--sp-scale));
  margin-top: calc(9px * var(--sp-scale));
  overflow: hidden; transition: max-height .3s ease, opacity .22s ease, margin-top .3s ease;
  max-height: 60vh; opacity: 1;
}
.sp-rules-card.is-shut .sp-rules-body { max-height: 0; opacity: 0; margin-top: 0; }

/* A single pass when the rules first turn up. Loud enough that nobody can say they
   never saw them; over quickly enough that it is not nagging somebody mid-match. */
@keyframes spRulesNudge {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--sp-accent) 0%, transparent); }
  12% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--sp-accent) 34%, transparent); }
  26% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--sp-accent) 0%, transparent); }
  38% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--sp-accent) 28%, transparent); }
  52% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--sp-accent) 0%, transparent); }
}
.sp-rules-card.is-new {
  animation: spRulesNudge 2.4s ease-out 1;
  border-color: color-mix(in srgb, var(--sp-accent) 45%, var(--sp-line));
}
.sp-rules-card.is-new .sp-rules-mark { animation: spRulesMark 2.4s ease-out 1; }
@keyframes spRulesMark {
  0%, 100% { transform: none; }
  10%, 30% { transform: rotate(-9deg); }
  20%, 40% { transform: rotate(9deg); }
}
@media (prefers-reduced-motion: reduce) {
  .sp-rules-card.is-new, .sp-rules-card.is-new .sp-rules-mark { animation: none; }
  .sp-rules-body { transition: none; }
}

/* ---------- the gamertag and the party code ----------
   Everything else on this page is explanation; this is the part the buyer has to carry
   into their game character for character. It gets its own framed block, type big
   enough to read off a phone at arm's length, and a copy button that looks like one.
   Not prefixed with .sp-live: the builder's preview renders the same markup, scaled
   down by --sp-scale, so the reseller styles the real thing. */
.sp-cred {
  position: relative; margin-top: 10px; padding: calc(11px * var(--sp-scale)) calc(13px * var(--sp-scale));
  border-radius: calc(var(--sp-r) * .85);
  border: 1px solid color-mix(in srgb, var(--sp-accent) 38%, var(--sp-line));
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--sp-accent) 11%, transparent), color-mix(in srgb, var(--sp-accent) 4%, transparent));
  overflow: hidden;
}
/* A bar of the accent down the leading edge, so the block reads as "this one matters"
   even at a glance, and in the themes whose cards are otherwise borderless. */
.sp-cred::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--sp-accent);
}
.sp-cred + .sp-cred { margin-top: calc(8px * var(--sp-scale)); }
.sp-cred-k {
  display: block; font-family: var(--sp-font-body);
  font-size: calc(8.5px * var(--sp-scale)); font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase;
  color: color-mix(in srgb, var(--sp-accent) 78%, var(--sp-fg));
}
.sp-cred-row { display: flex; align-items: center; gap: calc(8px * var(--sp-scale)); margin-top: calc(5px * var(--sp-scale)); }
.sp-cred-v {
  flex: 1; min-width: 0;
  font-family: ui-monospace,'SF Mono',Menlo,monospace;
  /* Shrinks with the screen so a long gamertag keeps to one line. The upper bound is
     the size it has always had on a desktop. */
  font-size: clamp(calc(9px * var(--sp-scale)), 4.4vw, calc(13px * var(--sp-scale)));
  font-weight: 700; line-height: 1.25;
  letter-spacing: -.01em; color: var(--sp-fg);
  overflow-wrap: anywhere; user-select: all; -webkit-user-select: all;
}
.sp-cred-v.is-long { font-size: clamp(calc(7.5px * var(--sp-scale)), 3.5vw, calc(11px * var(--sp-scale))); }
/* On a phone the button and the value cannot share a line without the value being
   broken in half, and half a gamertag is worse than useless — so the value takes the
   whole line and the button drops below it. */
@media (max-width: 460px) {
  .sp-live .sp-cred-row { flex-wrap: wrap; }
  .sp-live .sp-cred-v { flex: 1 1 100%; }
  .sp-live .sp-cred-copy { margin-left: auto; }
}
.sp-cred-copy {
  flex-shrink: 0; display: inline-flex; align-items: center; gap: 5px;
  padding: calc(6px * var(--sp-scale)) calc(9px * var(--sp-scale));
  border-radius: calc(var(--sp-r) * .6);
  border: 1px solid color-mix(in srgb, var(--sp-accent) 45%, transparent);
  background: color-mix(in srgb, var(--sp-accent) 14%, transparent);
  color: var(--sp-accent); cursor: pointer;
  font-family: var(--sp-font-body); font-size: calc(8.5px * var(--sp-scale));
  font-weight: 700; letter-spacing: .02em;
  transition: background .18s ease, border-color .18s ease, transform .12s ease;
}
.sp-cred-copy svg { width: calc(9px * var(--sp-scale)); height: calc(9px * var(--sp-scale)); }
.sp-cred-copy:hover { background: color-mix(in srgb, var(--sp-accent) 24%, transparent); border-color: var(--sp-accent); }
.sp-cred-copy:active { transform: scale(.97); }
/* Confirmation has to be unmistakable: on a phone the button label is easy to miss,
   so the whole block answers. */
.sp-cred.is-copied { border-color: var(--sp-accent); }
.sp-cred.is-copied .sp-cred-copy { background: var(--sp-accent); border-color: var(--sp-accent); color: var(--sp-on-accent, #0B0D12); }

/* Squared themes keep their corners here too. */
.shop-preview[data-corners="sharp"] .sp-cred,
.shop-preview[data-corners="sharp"] .sp-cred-copy { border-radius: 0; }

/* The link is bad, expired or cancelled: the one screen the builder cannot style away,
   because the buyer still has to be told plainly. */
.shop-preview[data-state="dead"] .sp-state[data-show="dead"] { display: block; }
.shop-preview[data-state="dead"] .sp-hero { display: none; }
.sp-live .sp-dead-icon { display: inline-grid; place-items: center; width: 40px; height: 40px; margin-bottom: 10px; border-radius: 50%; background: rgba(248,113,113,.14); color: #F87171; }
.sp-live .sp-dead-icon svg { width: 20px; height: 20px; }

/* While the link is being checked: no flash of the setup screen for a dead link. */
.shop-preview[data-state="loading"] .sp-state { display: none; }
.sp-live .sp-loading { padding: 34px 0; text-align: center; font-size: 13px; color: var(--sp-muted); }
.shop-preview:not([data-state="loading"]) .sp-loading { display: none; }
.shop-preview[data-state="loading"] .sp-hero, .shop-preview[data-state="loading"] .sp-foot { display: none; }

/* Powered-by, under the card. Small, outside the reseller's branding on purpose. */
.sp-poweredby { margin: 16px 0 0; text-align: center; font-family: 'Inter', system-ui, sans-serif; font-size: 11.5px; color: rgba(255,255,255,.3); }
.sp-poweredby a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

/* Stand-ins inside the builder's preview: they only have to look like the real
   controls lobby.html renders, so they are plain spans rather than live fields. */
.sp-plats-demo { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
.sp-plats-demo span { padding: 4px 8px; border-radius: 999px; border: 1px solid var(--sp-line); color: var(--sp-muted); font-size: calc(9px * var(--sp-scale)); font-weight: 600; }
.sp-plats-demo span.is-active { border-color: var(--sp-accent); background: color-mix(in srgb, var(--sp-accent) 15%, transparent); color: var(--sp-accent); }
