/* Reusable Prop Deck component.
 *
 * Mount with PropDeck.mount({ container, feedUrl, theme, ... }) — all
 * styles scope under .prop-deck so they don't collide with page-level
 * CSS.
 *
 * Theming: every color is driven by a CSS variable. Defaults below
 * produce the original dark look so existing surfaces (dashboard,
 * admin previews) need no changes. Pass `theme: "light"` to mount, or
 * add the class `prop-deck--light` to the container, to flip into
 * light mode (used by /ios/* surfaces).
 *
 * Visual reference: /stack-demo.html.  Pages must also load the
 * Swiper 11 bundle (CSS + JS) from CDN.
 */

/* --- Theme tokens (dark defaults) --- */
.prop-deck {
  --pd-surface:           #1a1d22;
  --pd-surface-hover:     #22262c;
  --pd-border:            #2a2f36;

  --pd-text-primary:      #e7e9ec;
  --pd-text-secondary:    var(--mtt-text-secondary);
  --pd-text-muted:        #9ca3af;
  --pd-text-faint:        #6b7280;
  --pd-text-divider:      #4b5563;
  --pd-text-bright:       var(--mtt-text-display);

  --pd-brand:             var(--mtt-brand-500);
  --pd-brand-strong:      var(--mtt-brand-300);
  --pd-brand-tint:        rgba(249, 115, 22, 0.12);
  --pd-brand-border:      rgba(249, 115, 22, 0.45);
  --pd-brand-strong-tint: rgba(249, 115, 22, 0.25);

  --pd-accent-amber:      var(--mtt-warning-text);
  --pd-success:           var(--mtt-success-text);
  --pd-live:              var(--mtt-danger-text);

  --pd-result-won-border: rgba(34, 197, 94, 0.45);
  --pd-result-lost-border: rgba(239, 68, 68, 0.4);

  --pd-overlay-soft:      color-mix(in srgb, var(--mtt-overlay) 5%, transparent);
  --pd-overlay-medium:    color-mix(in srgb, var(--mtt-overlay) 8%, transparent);
  --pd-overlay-strong:    color-mix(in srgb, var(--mtt-overlay) 22%, transparent);
  --pd-count-bg:          color-mix(in srgb, var(--mtt-overlay) 7%, transparent);

  --pd-info-bg:           rgba(56, 189, 248, 0.06);
  --pd-info-border:       rgba(56, 189, 248, 0.22);
  --pd-info-text:         #e5e7eb;
  --pd-info-text-strong:  #f1f5f9;
  --pd-info-meta:         var(--mtt-text-muted);
  --pd-info-link:         #93c5fd;
  --pd-info-error-text:   #fecaca;
  --pd-info-error-border: rgba(248, 113, 113, 0.4);
  --pd-info-error-bg:     rgba(248, 113, 113, 0.08);
}

/* --- Theme tokens (light) ---
   Dark is the default; these light values apply only on an explicit
   trigger: the `.prop-deck--light` opt-in (/ios/* surfaces) or a
   site-pinned data-theme="light" on a deck not marked .prop-deck--dark. */
.prop-deck--light,
:root[data-theme="light"] .prop-deck:not(.prop-deck--dark) {
  --pd-surface:           #ffffff;
  --pd-surface-hover:     #f5f5f7;
  --pd-border:            rgba(60, 60, 67, 0.16);

  --pd-text-primary:      #000000;
  --pd-text-secondary:    rgba(60, 60, 67, 0.85);
  --pd-text-muted:        rgba(60, 60, 67, 0.60);
  --pd-text-faint:        rgba(60, 60, 67, 0.40);
  --pd-text-divider:      rgba(60, 60, 67, 0.30);
  --pd-text-bright:       #000000;

  /* Brand orange stays. */
  --pd-brand:             var(--mtt-brand-500);
  --pd-brand-strong:      #c2410c;
  --pd-brand-tint:        rgba(249, 115, 22, 0.10);
  --pd-brand-border:      rgba(249, 115, 22, 0.55);
  --pd-brand-strong-tint: rgba(249, 115, 22, 0.20);

  --pd-accent-amber:      #b45309;
  --pd-success:           #15803d;
  --pd-live:              #b91c1c;

  --pd-result-won-border: rgba(34, 197, 94, 0.55);
  --pd-result-lost-border: rgba(239, 68, 68, 0.55);

  --pd-overlay-soft:      rgba(0, 0, 0, 0.04);
  --pd-overlay-medium:    rgba(0, 0, 0, 0.08);
  --pd-overlay-strong:    rgba(0, 0, 0, 0.16);
  --pd-count-bg:          rgba(0, 0, 0, 0.05);

  --pd-info-bg:           rgba(56, 189, 248, 0.10);
  --pd-info-border:       rgba(14, 116, 144, 0.30);
  --pd-info-text:         #0f172a;
  --pd-info-text-strong:  #0f172a;
  --pd-info-meta:         rgba(15, 23, 42, 0.55);
  --pd-info-link:         #0369a1;
  --pd-info-error-text:   #991b1b;
  --pd-info-error-border: rgba(185, 28, 28, 0.35);
  --pd-info-error-bg:     rgba(248, 113, 113, 0.10);
}

/* No OS-driven auto light mode: the deck defaults to dark and only
   goes light on an explicit trigger — the `.prop-deck--light` opt-in
   (ios) or a site-pinned data-theme="light" (both handled by the
   selector on the light token block above). */

.prop-deck {
  /* Container is whatever element the page provides. */
  display: block;
  width: 100%;
}

/* --- Day strip --- */
.prop-deck .day-strip {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  padding-block: 4px 12px;
  padding-inline: 50vw;
  margin-bottom: 16px;
}
.prop-deck .day-strip::-webkit-scrollbar { display: none; }
.prop-deck .day-chip {
  flex-shrink: 0;
  background: var(--pd-surface);
  border: 1px solid var(--pd-border);
  color: var(--pd-text-muted);
  border-radius: var(--mtt-radius-md);
  padding: 6px 10px;
  font-size: 0.8rem;
  font-weight: 500;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 56px;
  line-height: 1.15;
  font-family: inherit;
}
.prop-deck .day-chip:hover { background: var(--pd-surface-hover); }
.prop-deck .day-chip .dow {
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  opacity: 0.65;
}
.prop-deck .day-chip.is-today .dow { color: var(--pd-accent-amber); opacity: 1; }
.prop-deck .day-chip.is-active {
  background: var(--pd-brand-tint);
  border-color: var(--pd-brand);
  color: var(--pd-brand-strong);
}
.prop-deck .day-chip.is-active .dow { color: var(--pd-brand-strong); opacity: 1; }

/* --- Event strip --- */
.prop-deck .event-strip {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  touch-action: pan-x;
  -webkit-overflow-scrolling: touch;
  scroll-behavior: smooth;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  /* Right-only padding so the last chip doesn't butt against the edge;
     chips start flush-left at position 0. */
  padding-block: 0 4px;
  padding-inline-start: 0;
  padding-inline-end: 24px;
  margin-bottom: 12px;
}
.prop-deck .event-strip::-webkit-scrollbar { display: none; }
.prop-deck .event-strip[hidden] { display: none; }
.prop-deck .event-chip {
  flex-shrink: 0;
  scroll-snap-align: start;
  background: var(--pd-surface);
  border: 1px solid var(--pd-border);
  border-radius: var(--mtt-radius-pill);
  padding: 5px 10px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
  font-size: var(--mtt-fs-xs);
  color: var(--pd-text-secondary);
  font-family: inherit;
  font-weight: var(--mtt-fw-medium);
  letter-spacing: 0.02em;
  transition: border-color 0.15s, background 0.15s, color 0.15s;
}
.prop-deck .event-chip:hover { background: var(--pd-surface-hover); }
.prop-deck .event-chip .team-logo {
  width: 14px;
  height: 14px;
  object-fit: contain;
  border-radius: 3px;
  flex-shrink: 0;
}
.prop-deck .event-chip .vs { color: var(--pd-text-divider); font-weight: var(--mtt-fw-normal); }
.prop-deck .event-chip .count {
  margin-left: 3px;
  background: var(--pd-count-bg);
  border-radius: var(--mtt-radius-pill);
  padding: 1px 7px;
  font-size: 0.65rem;
  font-weight: var(--mtt-fw-semibold);
  color: var(--pd-text-muted);
  letter-spacing: 0;
}
.prop-deck .event-chip.is-active {
  background: var(--pd-brand-tint);
  border-color: var(--pd-brand);
  color: var(--pd-brand-strong);
}
.prop-deck .event-chip.is-active .count {
  background: var(--pd-brand-strong-tint);
  color: var(--pd-brand-strong);
}

/* --- Stack column --- */
.prop-deck .stack {
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  overflow: visible;
}
.prop-deck .swiper {
  width: 100%;
  /* Baseline floor so the deck has a visible height before slides
     hydrate.  After mount, equalizeSlideHeights() sets an explicit
     inline height equal to the tallest slide so every card in the
     stack shares that height. */
  min-height: 360px;
  overflow: visible;
}
.prop-deck .swiper-slide {
  border-radius: 16px;
  background: var(--pd-surface);
  border: 1px solid var(--pd-border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--pd-text-faint);
  font-size: var(--mtt-fs-lg);
  user-select: none;
}

/* --- Prop slide content --- */
.prop-deck .swiper-slide.prop {
  flex-direction: column;
  align-items: stretch;
  /* `.prop-top` (the matchup/question/insight group) carries `flex: 1`
     and centers its own children, so any slack equalizeSlideHeights
     leaves above the bottom action stack splits evenly above and
     below the top group.  `.sides`, `.commit-btn`, and `.side-updated`
     are stacked siblings after `.prop-top` and sit flush with the
     bottom of the slide. */
  justify-content: flex-start;
  padding: 16px;
  color: var(--pd-text-primary);
  text-align: left;
  position: relative;
}
/* Optional per-card event footer.  Opted in via
   PropDeck.mount({ showEventStamp: true }) — sits BELOW the hero image
   inside `.prop-top`, between the hero and the question.  Single
   centered, muted, small line:
     "Sat May 16, 6:11 EDT • CIN @ CLE"
   The whole line is wrapped in one anchor when sport + externalIds.espn
   resolve so any click opens the ESPN game page in a new tab.  Hover
   brightens to the surface's primary text color so it reads as a link. */
/* Source event badge — shown on daily pack props to surface which game
   the prop belongs to.  When the prop came from a specific event pack the
   badge is an <a> link (.prop-source-badge--link) so fans can navigate
   directly to that pack. */
.prop-deck .swiper-slide.prop .prop-source-badge {
  text-align: center;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--pd-text-muted);
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  letter-spacing: 0.02em;
  text-decoration: none;
}
.prop-deck .swiper-slide.prop .prop-source-badge--link {
  cursor: pointer;
}
.prop-deck .swiper-slide.prop .prop-source-league {
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--pd-brand, var(--mtt-brand-500));
  background: rgba(249, 115, 22, 0.1);
  border-radius: 4px;
  padding: 1px 5px;
}
.prop-deck .swiper-slide.prop .prop-source-sep {
  font-size: 0.65rem;
  color: var(--pd-text-muted);
  opacity: 0.6;
}
.prop-deck .swiper-slide.prop .prop-source-time {
  font-size: 0.65rem;
  font-weight: 500;
  color: var(--pd-text-muted);
  opacity: 0.75;
  white-space: nowrap;
}
/* Mini team pill inside the source badge: coloured dot + logo + abbr */
.prop-deck .swiper-slide.prop .source-team-pill {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  background: color-mix(in srgb, var(--mtt-overlay) 8%, transparent);
  border-radius: 20px;
  padding: 2px 7px 2px 3px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: #fff;
  line-height: 1;
}
.prop-deck .swiper-slide.prop .source-team-pill--colored {
  background: color-mix(in srgb, var(--team-color, #555) 22%, transparent);
}
.prop-deck .swiper-slide.prop .source-team-pill__logo {
  width: 16px;
  height: 16px;
  object-fit: contain;
  border-radius: 50%;
  background: color-mix(in srgb, var(--mtt-overlay) 8%, transparent);
  flex-shrink: 0;
}
.prop-deck .swiper-slide.prop .source-team-pill__abbr {
  font-size: 0.68rem;
  font-weight: 700;
}

.prop-deck .swiper-slide.prop .event-stamp {
  text-align: center;
  font-size: 0.78rem;
  color: var(--pd-text-muted);
  /* No bottom margin — `.question` below carries its own top margin,
     and flex items don't collapse adjacent margins so any value here
     stacks on top of the question's gap. */
  margin: 6px 0 0;
  font-variant-numeric: tabular-nums;
}
.prop-deck .swiper-slide.prop .event-stamp a {
  color: inherit;
  text-decoration: none;
}
.prop-deck .swiper-slide.prop .event-stamp a:hover {
  color: var(--pd-text-primary);
}
.prop-deck .swiper-slide.prop .event-stamp .sep {
  opacity: 0.7;
  margin: 0 4px;
}

/* The top "group" — matchup hero, question, insight controls + panel.
   Eats remaining slide height (`flex: 1`) and centers its children
   vertically so the group sits with equal space above and below
   between the slide's top padding and the action stack. */
.prop-deck .prop-top {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Belt-and-braces against weird flex children pushing past the
     wrapper — equalizeSlideHeights pins every slide to a fixed
     height, so any overflow clips inside `.info-panel`'s own
     max-height instead of breaking the page. */
  min-height: 0;
}

.prop-deck .event-status-badge {
  align-self: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 8px;
  padding: 4px 10px;
  border-radius: var(--mtt-radius-pill, 999px);
  border: 1px solid rgba(251, 191, 36, 0.32);
  background: rgba(251, 191, 36, 0.12);
  color: #fbbf24;
  font-size: var(--mtt-fs-eyebrow, 0.72rem);
  font-weight: var(--mtt-fw-semibold, 600);
  letter-spacing: 0.08em;
  line-height: 1;
  text-transform: uppercase;
}

.prop-deck .event-status-badge--cancelled {
  border-color: rgba(248, 113, 113, 0.35);
  background: rgba(248, 113, 113, 0.1);
  color: var(--pd-danger, #f87171);
}

.prop-deck .event-status-badge--final {
  border-color: rgba(147, 197, 253, 0.3);
  background: rgba(147, 197, 253, 0.09);
  color: var(--pd-info-link);
}

/* Top-right "Detail" escape hatch that opens /props/:slug.  Pinned to
   the slide corner so it sits above the meta row without consuming
   layout width on narrow cards. */
.prop-deck .prop-detail-link {
  position: absolute;
  top: 10px;
  right: 12px;
  font-size: 0.68rem;
  font-weight: var(--mtt-fw-medium);
  letter-spacing: 0.02em;
  color: var(--pd-text-muted, var(--mtt-text-muted));
  text-decoration: none;
  padding: 3px 8px;
  border-radius: var(--mtt-radius-sm);
  border: 1px solid var(--pd-border, color-mix(in srgb, var(--mtt-overlay) 12%, transparent));
  background: color-mix(in srgb, var(--mtt-overlay) 3%, transparent);
  z-index: 2;
  white-space: nowrap;
}
.prop-deck .prop-detail-link:hover {
  color: var(--pd-brand-strong, var(--mtt-brand-400));
  border-color: var(--pd-brand-border, rgba(249,115,22,0.45));
  background: rgba(249, 115, 22, 0.08);
}
/* Admin-only: the "Detail ↗" escape hatch is debugging chrome — hide
   for fans, leave visible for admins.  Same .prop-deck--admin toggle
   the Restack + per-card Refresh buttons use. */
.prop-deck .prop-detail-link { display: none; }
.prop-deck--admin .prop-detail-link { display: inline-block; }
.prop-deck .meta {
  font-size: var(--mtt-fs-xs);
  color: var(--pd-text-faint);
  font-weight: var(--mtt-fw-medium);
  letter-spacing: var(--mtt-tracking-wide);
  text-transform: uppercase;
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
}
.prop-deck .meta .team {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--pd-text-secondary);
}
.prop-deck .meta .team-logo {
  width: 18px;
  height: 18px;
  object-fit: contain;
  border-radius: 4px;
  flex-shrink: 0;
  background: transparent;
}
.prop-deck .meta .vs { color: var(--pd-text-divider); letter-spacing: 0; }
.prop-deck .meta .league { color: var(--pd-text-muted); }
.prop-deck .meta .live { color: var(--pd-live); }
.prop-deck .meta .takes {
  color: var(--pd-text-muted);
  font-variant-numeric: tabular-nums;
}
/* Admin-only: the "· N takes" chip in the meta row is operational
   data fans don't need crowding the matchup header.  Same
   .prop-deck--admin toggle as the other admin-only deck chrome. */
.prop-deck .meta .takes { display: none; }
.prop-deck--admin .meta .takes { display: inline; }
/* When fan view hides the takes chip and the prop has no LIVE / FINAL
   state to show either, the .meta flex container is left empty but
   still occupies a line-height's worth of vertical space — reads as a
   thin empty bar above the hero.  Collapse the row entirely when its
   only renderable child would have been the (now hidden) takes chip.
   Admin view always shows .takes, so this never triggers there. */
.prop-deck:not(.prop-deck--admin) .meta:not(:has(> :not(.takes))) {
  display: none;
}
.prop-deck .question {
  font-size: 1.05rem;
  font-weight: var(--mtt-fw-medium);
  line-height: 1.35;
  color: var(--pd-text-primary);
  margin: 4px 0;
  text-align: center;
  /* No `flex: 1` — the question hugs its own line-height so cards
     without an insight panel don't stretch the title vertically. */
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Live-stat chip: server-stamped current in-game number for the prop
   (e.g. "● Live · 18 PTS · vs 29.5" on an SGA points O/U mid-game).
   Sits between the question and the side buttons.  Direction-neutral
   trend colors encode CURRENT vs LINE (over = green, under = red),
   not the viewer's pick — see the long-form note in
   _renderLiveStatChip in prop-stack.js. */
.prop-deck .live-stat {
  display: inline-flex;
  align-items: center;
  align-self: center;
  gap: 6px;
  margin: 6px auto 0;
  padding: 4px 10px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--pd-surface, #111) 70%, transparent);
  border: 1px solid color-mix(in srgb, var(--pd-text-primary, #fff) 12%, transparent);
  font-size: var(--mtt-fs-eyebrow, 0.72rem);
  letter-spacing: var(--mtt-tracking-wide, 0.04em);
  line-height: 1;
  color: var(--pd-text-secondary, #b0b3b8);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.prop-deck .live-stat__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  /* Subtle pulse — matches the box-score's LIVE pill animation
     (`mttLivePulse` in landing/index.html) at a smaller scale. */
  box-shadow: 0 0 0 0 currentColor;
  animation: pdLiveStatPulse 1.8s ease-out infinite;
  opacity: 0.85;
}
.prop-deck .live-stat__label {
  text-transform: uppercase;
  font-weight: var(--mtt-fw-semibold, 600);
  letter-spacing: 0.08em;
  opacity: 0.85;
}
.prop-deck .live-stat__value {
  color: var(--pd-text-primary, #fff);
  font-weight: var(--mtt-fw-semibold, 600);
}
.prop-deck .live-stat__line {
  opacity: 0.6;
  font-weight: var(--mtt-fw-regular, 400);
}

/* Trend tint: colors the dot + label + border, leaves value bright
   white so the number is always the most-readable element regardless
   of trend.  Push (current === line) keeps the neutral baseline. */
.prop-deck .live-stat[data-trend="over"] {
  color: var(--pd-success, #34d399);
  border-color: color-mix(in srgb, var(--pd-success, #34d399) 40%, transparent);
  background: color-mix(in srgb, var(--pd-success, #34d399) 8%, var(--pd-surface, #111));
}
.prop-deck .live-stat[data-trend="under"] {
  color: var(--pd-danger, #f87171);
  border-color: color-mix(in srgb, var(--pd-danger, #f87171) 40%, transparent);
  background: color-mix(in srgb, var(--pd-danger, #f87171) 8%, var(--pd-surface, #111));
}

/* Final state: drop the pulse, fade the chip slightly so the eye
   reads it as "settled" rather than "live updating".  The trend
   color is preserved — a final value over the line stays green so
   the chip doubles as a quick "did the over hit?" cue. */
.prop-deck .live-stat[data-state="final"] {
  opacity: 0.85;
}
.prop-deck .live-stat[data-state="final"] .live-stat__dot {
  display: none;
}

@keyframes pdLiveStatPulse {
  0%   { box-shadow: 0 0 0 0 currentColor; }
  70%  { box-shadow: 0 0 0 5px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .prop-deck .live-stat__dot { animation: none; }
}
.prop-deck .hero {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin: 4px 0 6px;
}
.prop-deck .hero img {
  width: 96px;
  height: 96px;
  object-fit: cover;
  background: var(--pd-surface);
}
/* Player headshots: circle-crop the athlete cutout and lay a white
   plate behind it so transparent PNGs read cleanly on dark surfaces. */
.prop-deck .hero-player img {
  border-radius: 50%;
  background: #fff;
}
.prop-deck .hero-matchup img {
  width: 64px;
  height: 64px;
  object-fit: contain;
  background: transparent;
  border: none;
}
/* Team-color logo wrapper.  Background colour is inlined per-card from
   the team's primary brand colour; the wrapper just provides the shape,
   padding, and centering so the logo sits cleanly inside the tint. */
.prop-deck .hero .hero-logo-wrap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--pd-surface);
  border-radius: var(--mtt-radius-xl);
  padding: 8px;
  box-sizing: border-box;
}
.prop-deck .hero-team .hero-logo-wrap {
  width: 96px;
  height: 96px;
}
.prop-deck .hero-team .hero-logo-wrap img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: transparent;
}
.prop-deck .hero-matchup .hero-logo-wrap {
  width: 64px;
  height: 64px;
  border-radius: var(--mtt-radius-lg);
  padding: 6px;
}
.prop-deck .hero-matchup .hero-logo-wrap img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: transparent;
}
.prop-deck .hero-vs {
  color: var(--pd-text-divider);
  font-size: 0.9rem;
  font-weight: var(--mtt-fw-medium);
}
.prop-deck .hero-initials {
  width: 96px;
  height: 96px;
  background: var(--pd-surface);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6rem;
  font-weight: var(--mtt-fw-semibold);
  letter-spacing: var(--mtt-tracking-wide);
  color: var(--pd-text-muted);
}
.prop-deck .hero-matchup .hero-initials {
  width: 64px;
  height: 64px;
  font-size: 1.1rem;
  border: none;
  background: transparent;
}
/* "Updated Xm ago" stamp + per-card refresh link, centered under the
   commit button.  Stamp is dim and time-formatted; refresh link is an
   inline button styled to look like a hyperlink. */
.prop-deck .side-updated {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  flex-wrap: wrap;
  font-size: 0.66rem;
  letter-spacing: var(--mtt-tracking-wide);
  text-transform: uppercase;
  color: var(--pd-text-secondary);
  padding: 8px 4px 2px;
  font-variant-numeric: tabular-nums;
}
.prop-deck .side-updated .stamp { opacity: 0.7; }
/* Pack-membership chip — a touch more muted than the live "Updated"
   stamp so the eye treats it as static lifecycle context rather than
   the live odds heartbeat right next to it.  Cursor hint signals
   the hover tooltip (absolute ISO via `title` attr). */
.prop-deck .side-updated .stamp-added {
  opacity: 0.55;
  cursor: help;
}
/* Closed chip — only renders on cards that are currently locked
   because the book pulled the line (p.unverified === true).  Tinted
   with the deck's "danger" hue so it reads as a state badge rather
   than a generic lifecycle stamp; full opacity because it's the
   most actionable piece of context on a locked card ("this market
   went away 3m ago — try refreshing"). */
.prop-deck .side-updated .stamp-closed {
  opacity: 0.85;
  cursor: help;
  color: var(--pd-danger, #ef4444);
  font-weight: var(--mtt-fw-semibold, 600);
}
.prop-deck .side-updated .sep { opacity: 0.4; }
/* The "Added" and "Updated Xm ago" stamps are global — every viewer
   sees when a prop joined the pack and when the line was last
   refreshed (live cards) or settled (graded cards).  The "↻ Refresh
   prices" button stays admin-only because it consumes Odds-API
   credits; the .prop-deck--admin class is stamped on the container
   by /api/auth/me (see prop-stack.js).
   We only hide the "·" separator that sits IMMEDIATELY BEFORE the
   refresh button (`.sep:has(+ .refresh-pair)`), so the separator
   between Added and Updated still renders for non-admin viewers.
   `:has()` is supported in every browser the deck targets
   (Chrome/Safari/Firefox shipped in 2022–2024); the older blanket
   `.sep { display: none }` rule was over-broad once the footer grew
   from two chips to three. */
.prop-deck:not(.prop-deck--admin) .side-updated .refresh-pair,
.prop-deck:not(.prop-deck--admin) .side-updated .sep:has(+ .refresh-pair) {
  display: none;
}
.prop-deck .side-updated .refresh-pair {
  appearance: none;
  background: transparent;
  border: none;
  font: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  color: var(--pd-text-secondary);
  cursor: pointer;
  padding: 0;
  text-decoration: underline;
  text-underline-offset: 2px;
  opacity: 0.8;
}
.prop-deck .side-updated .refresh-pair:hover { color: var(--pd-brand); opacity: 1; }
.prop-deck .side-updated .refresh-pair:disabled { cursor: default; opacity: 0.5; text-decoration: none; }

/* Modal shown when a per-card refresh discovers the prop has been
   pulled from the book.  Single OK button; closing the modal removes
   the card from the deck. */
.prop-deck-modal {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  padding: 20px;
}
.prop-deck-modal .box {
  background: var(--mtt-surface-panel);
  border: 1px solid color-mix(in srgb, var(--mtt-overlay) 12%, transparent);
  border-radius: var(--mtt-radius-2xl);
  padding: 22px 22px 18px;
  max-width: 360px;
  width: 100%;
  text-align: center;
  color: var(--mtt-text-bright);
}
.prop-deck-modal .box .msg {
  font-size: var(--mtt-fs-md);
  line-height: 1.4;
  margin-bottom: 16px;
}
.prop-deck-modal .box .actions {
  display: flex;
  gap: 8px;
  justify-content: center;
  flex-wrap: wrap;
}
.prop-deck-modal .box .ok,
.prop-deck-modal .box .restack {
  appearance: none;
  border: none;
  font: inherit;
  font-weight: var(--mtt-fw-semibold);
  padding: 8px 22px;
  border-radius: var(--mtt-radius-md);
  cursor: pointer;
}
.prop-deck-modal .box .ok {
  background: var(--pd-brand);
  color: var(--mtt-surface-base);
}
.prop-deck-modal .box .restack {
  background: color-mix(in srgb, var(--mtt-overlay) 8%, transparent);
  color: var(--mtt-text-bright);
  border: 1px solid color-mix(in srgb, var(--mtt-overlay) 16%, transparent);
}
.prop-deck-modal .box .ok:hover,
.prop-deck-modal .box .restack:hover { filter: brightness(1.12); }
.prop-deck .sides {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  /* No `margin-top: auto` needed — `.prop-top` consumes the slack
     above (via `flex: 1`) so `.sides` and the rest of the action
     stack naturally fall to the bottom of the card. */
}
.prop-deck .side {
  appearance: none;
  font: inherit;
  text-align: center;
  padding: 10px 8px;
  border-radius: var(--mtt-radius-lg);
  border: 1px solid var(--pd-border);
  background: var(--pd-surface-hover);
  color: var(--pd-text-primary);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  /* Center every flex child (avatar slot, .desc, .odds, .win, pile)
     instead of stretching them across the side's full width — keeps
     each line visually centered in the take regardless of its
     natural content width. */
  align-items: center;
  gap: 2px;
}
@media (hover: hover) {
  .prop-deck .side:hover:not(:disabled) {
    border-color: var(--pd-brand-border);
    background: var(--pd-brand-tint);
  }
}
.prop-deck .side:disabled { cursor: default; opacity: 0.65; }
/* Settled-result highlight — used on final-event packs to mark which
   side cashed.  `side-winner` gets a green tint + brighter border so
   it pops without the dim treatment; `side-loser` is muted but still
   readable.  Override the `:disabled` opacity floor so the contrast
   between winner and loser survives locking. */
.prop-deck .side.side-winner {
  border-color: rgba(34, 197, 94, 0.6);
  background: rgba(34, 197, 94, 0.12);
  color: var(--pd-text-bright, var(--mtt-text-display));
  opacity: 1;
}
.prop-deck .side.side-winner:disabled { opacity: 1; }
.prop-deck .side.side-winner .desc { color: #bbf7d0; }
.prop-deck .side.side-loser {
  border-color: rgba(148, 163, 184, 0.18);
  background: rgba(148, 163, 184, 0.04);
  color: var(--pd-text-secondary);
  opacity: 0.55;
}
.prop-deck .side .desc {
  font-size: 0.85rem;
  font-weight: var(--mtt-fw-medium);
  line-height: 1.25;
}
.prop-deck .side .odds {
  font-size: var(--mtt-fs-xs);
  color: var(--pd-accent-amber);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.prop-deck .side .win {
  font-size: var(--mtt-fs-eyebrow);
  font-weight: var(--mtt-fw-medium);
  color: var(--pd-success);
  letter-spacing: 0.02em;
  margin-top: 1px;
}
/* Terminal-state variants of the `.win` chip — replace the
   "Win N.N" payout preview once the prop is graded.  Bolder,
   uppercased, and slightly larger so they read as final-status
   badges instead of projected numbers.  `--won` keeps the existing
   green color from `.win`; `--lost` swaps in the danger color so
   the two sides read at a glance. */
/* Graded-prop verdict chips reuse the base `.win` typography so they
   sit in the same slot as the active "Win N.N" chip with no visual
   weight jump.  Only color encodes the verdict: the winning side
   keeps the green `.win` color, the losing side flips to danger red. */
.prop-deck .side .win--lost {
  color: var(--pd-danger, var(--mtt-danger-text, #f87171));
}
/* Avatar pile — recent takers on this side, stacked horizontally with
   a 1px white border so each face still pops on the dark card. */
.prop-deck .side .taker-pile {
  display: inline-flex;
  align-items: center;
  margin-top: 6px;
  padding-left: 5px; /* offset so the first -ml on a dot doesn't clip */
}
.prop-deck .side .taker-dot {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 1px solid var(--mtt-text-display);
  background: var(--pd-surface-sub, #222);
  margin-left: -5px;
  object-fit: cover;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6rem;
  font-weight: var(--mtt-fw-semibold);
  color: var(--pd-text-primary);
  flex: 0 0 auto;
  overflow: hidden;
  line-height: 1;
}
.prop-deck .side .taker-dot.fallback {
  background: rgba(249, 115, 22, 0.18);
  color: var(--pd-accent-amber, var(--mtt-brand-300));
}
.prop-deck .side .taker-dot.overflow {
  background: color-mix(in srgb, var(--mtt-overlay) 8%, transparent);
  color: var(--pd-text-muted, var(--mtt-text-muted));
  font-size: 0.58rem;
  letter-spacing: 0.02em;
}
.prop-deck .side.selected {
  border-color: var(--pd-brand);
  background: var(--pd-brand-tint);
}
.prop-deck .side.selected .desc { color: var(--pd-brand-strong); }
/* "Verified" avatar — appears at the top of the side the fan took so
   the card reads as a confirmed pick at a glance.  Both grid cells grow
   to match the taller side via the existing 1fr 1fr layout, so the
   un-picked side gains the same vertical headroom for visual balance. */
.prop-deck .side .me-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--pd-surface-sub, var(--mtt-surface-raise));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: center;
  /* Top-anchored within the side button (no auto top margin): the
     viewer's avatar sits in the same vertical position regardless of
     whether the followed-fan pile renders below it.  Any leftover
     slack from equalizeSlideHeights collects at the bottom of the
     button instead. */
  margin: 6px 0 0;
  overflow: hidden;
  flex: 0 0 auto;
}
.prop-deck .side .me-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Empty placeholder slot — used on un-picked / un-pending sides so all
   cards keep a consistent height regardless of pick state.  Subtle
   dashed ring hints that the slot will fill when this side becomes
   the fan's pick. */
.prop-deck .side .me-avatar.is-empty {
  background: transparent;
  border: 1px dashed rgba(148, 163, 184, 0.35);
}
.prop-deck .side .me-avatar .me-avatar-initial {
  font-size: 0.85rem;
  font-weight: var(--mtt-fw-semibold);
  color: var(--pd-brand-strong, var(--pd-brand));
  line-height: 1;
  text-transform: uppercase;
}

/* Followed-fan pile — rendered below .me-avatar inside each side button
   when someone the viewer follows has taken that side.  A pile of 3
   reads as one social chip, with +N for overflow. */
.prop-deck .side .fan-pile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 4px 0 0;
  min-height: 22px;
}
.prop-deck .side .fan-pile-avatar {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2px solid var(--pd-surface, var(--mtt-surface-base));
  background: var(--pd-surface-sub, var(--mtt-surface-raise));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  flex: 0 0 auto;
}
.prop-deck .side .fan-pile-avatar + .fan-pile-avatar,
.prop-deck .side .fan-pile-avatar + .fan-pile-more,
.prop-deck .side .fan-pile-avatar:has(+ .fan-pile-more) ~ .fan-pile-more {
  margin-left: -6px;
}
.prop-deck .side .fan-pile-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.prop-deck .side .fan-pile-initial {
  font-size: 0.62rem;
  font-weight: var(--mtt-fw-semibold);
  color: var(--pd-text-primary);
  line-height: 1;
  text-transform: uppercase;
}
.prop-deck .side .fan-pile-more {
  height: 22px;
  min-width: 22px;
  padding: 0 5px;
  border-radius: 11px;
  background: var(--pd-surface-sub, var(--mtt-surface-raise));
  border: 2px solid var(--pd-surface, var(--mtt-surface-base));
  color: var(--pd-text-secondary);
  font-size: 0.62rem;
  font-weight: var(--mtt-fw-semibold);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}

/* Pending = user tapped this side but hasn't pressed "Make this take" yet.
   Visually distinct from .selected so a fan in the middle of changing a
   pick can tell which side is the committed one and which is just queued. */
.prop-deck .side.pending {
  border-color: var(--pd-brand);
  background: transparent;
  outline: 2px dashed var(--pd-brand);
  outline-offset: -4px;
}
.prop-deck .side.pending .desc { color: var(--pd-brand-strong); }

/* Unverified state — the odds book couldn't confirm this market when
   we built the deck (event already final, market fetch failed, etc.).
   Subtle muted border so the card still reads as visually distinct
   from a live one; the disabled commit button ("Closed") and the
   .side:disabled treatment on the side buttons carry the messaging. */
.prop-deck .swiper-slide.prop.is-unverified {
  border-color: rgba(148, 163, 184, 0.28);
}

/* "Win tokens changed" prompt — shown when sandbox-take returns 409
   price_changed.  Modal overlay: takes over the screen and asks the
   fan to accept the new win-token amount before the take is recorded. */
.price-change-prompt {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(2px);
  font-family: var(--mtt-font-sans, inherit);
  animation: pcp-fade 0.18s ease-out;
}
.price-change-prompt[hidden] { display: none; }
@keyframes pcp-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes pcp-pop  { from { transform: scale(0.96); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.price-change-prompt .panel {
  position: relative;
  width: 100%;
  max-width: 420px;
  background: var(--mtt-surface-panel);
  border: 1px solid color-mix(in srgb, var(--mtt-overlay) 10%, transparent);
  border-radius: 16px;
  padding: 22px 22px 20px;
  color: var(--mtt-text-bright);
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.6);
  text-align: center;
  animation: pcp-pop 0.2s cubic-bezier(.2,.9,.3,1);
}
.price-change-prompt .lead {
  font-size: 0.68rem;
  font-weight: var(--mtt-fw-semibold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--mtt-warning-text);
  margin: 0 0 14px;
}
.price-change-prompt .delta {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 14px;
  font-variant-numeric: tabular-nums;
  margin-bottom: 12px;
}
.price-change-prompt .delta .old {
  font-size: 1.1rem;
  font-weight: var(--mtt-fw-medium);
  color: var(--mtt-text-muted);
  text-decoration: line-through;
}
.price-change-prompt .delta .arrow {
  color: var(--mtt-text-soft);
  font-size: 1.1rem;
}
.price-change-prompt .delta .new {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-size: 1.05rem;
  font-weight: var(--mtt-fw-semibold);
  color: var(--mtt-success-text);
}
.price-change-prompt .delta .new.is-down { color: var(--mtt-danger-text); }
.price-change-prompt .delta .new .amt {
  font-size: var(--mtt-fs-2xl);
  font-weight: var(--mtt-fw-semibold);
  line-height: 1;
}
.price-change-prompt .note {
  font-size: var(--mtt-fs-sm);
  color: var(--mtt-text-muted);
  line-height: 1.45;
  padding: 0 8px;
  margin-bottom: 18px;
}
.price-change-prompt .row {
  display: flex;
  gap: 10px;
  justify-content: center;
}
.price-change-prompt button {
  appearance: none;
  font: inherit;
  font-weight: var(--mtt-fw-semibold);
  font-size: 0.92rem;
  padding: 11px 20px;
  border-radius: var(--mtt-radius-lg);
  cursor: pointer;
  border: 1px solid transparent;
  transition: background 0.15s, border-color 0.15s, transform 0.08s;
}
.price-change-prompt button:active { transform: translateY(1px); }
.price-change-prompt button.accept {
  background: var(--mtt-brand-500);
  color: var(--mtt-surface-base);
}
.price-change-prompt button.accept:hover { background: var(--mtt-brand-400); }
.price-change-prompt button.dismiss {
  background: transparent;
  color: var(--mtt-text-muted);
  border-color: color-mix(in srgb, var(--mtt-overlay) 15%, transparent);
}
.price-change-prompt button.dismiss:hover { color: var(--mtt-text-display); border-color: color-mix(in srgb, var(--mtt-overlay) 25%, transparent); }
@media (max-width: 360px) {
  .price-change-prompt .row { flex-direction: column-reverse; }
  .price-change-prompt button { width: 100%; }
}

.prop-deck .commit-actions {
  /* No horizontal padding so the commit button's outer edges line up
     with the left/right edges of the `.sides` grid above — both are
     direct children of the slide, which already supplies a 16px
     content gutter via its own padding. */
  padding: 12px 0 14px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}
.prop-deck .commit-take {
  width: 100%;
  padding: 12px 16px;
  background: var(--pd-brand);
  color: var(--pd-on-brand, var(--mtt-text-display));
  border: none;
  border-radius: var(--mtt-radius-lg);
  font-weight: var(--mtt-fw-semibold);
  font-size: var(--mtt-fs-md);
  cursor: pointer;
  letter-spacing: 0.02em;
  transition: background 120ms ease, opacity 120ms ease;
}
.prop-deck .commit-take:hover:not(:disabled) {
  background: var(--pd-brand-strong, var(--pd-brand));
}
.prop-deck .commit-take:disabled {
  background: var(--pd-surface-sub, #222);
  color: var(--pd-text-muted);
  cursor: not-allowed;
  opacity: 0.7;
}

/* Take receipt — small table-style block beneath the commit button that
   shows who made the take and when, so the deck doubles as a quick
   confirmation surface.  Hidden until a take is committed. */
.prop-deck .take-receipt {
  margin-top: 10px;
  width: 100%;
  background: var(--pd-surface-sub, var(--mtt-surface-raise));
  border: 1px solid var(--pd-border, #2a2a2a);
  border-radius: var(--mtt-radius-md);
  padding: 6px 12px;
}
.prop-deck .take-receipt-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 5px 0;
}
.prop-deck .take-receipt-row + .take-receipt-row {
  border-top: 1px solid var(--pd-border, #2a2a2a);
}
.prop-deck .take-receipt-label {
  color: var(--pd-text-muted);
  text-transform: uppercase;
  letter-spacing: var(--mtt-tracking-wide);
  font-size: 0.65rem;
  font-weight: var(--mtt-fw-semibold);
}
.prop-deck .take-receipt-value {
  color: var(--pd-text, #f3f3f3);
  font-size: 0.78rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.prop-deck .take-receipt-link {
  color: var(--pd-brand-strong);
  text-decoration: underline;
  text-decoration-color: rgba(249, 115, 22, 0.45);
  text-underline-offset: 2px;
}
.prop-deck .take-receipt-link:hover {
  color: var(--pd-brand);
  text-decoration-color: var(--pd-brand);
}
.prop-deck .swiper-slide.result-won  { border-color: var(--pd-result-won-border); }
.prop-deck .swiper-slide.result-lost { border-color: var(--pd-result-lost-border); }

/* "Get info" affordance */
.prop-deck .info-action {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 6px;
  padding: 4px 0 6px;
}
.prop-deck .info-level {
  appearance: none;
  background: var(--pd-overlay-soft);
  color: var(--pd-text-secondary);
  border: 1px solid var(--pd-overlay-medium);
  border-radius: var(--mtt-radius-pill);
  padding: 3px 22px 3px 10px;
  font: inherit;
  font-size: var(--mtt-fs-xs);
  font-weight: var(--mtt-fw-medium);
  cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 12px) 50%, calc(100% - 7px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.prop-deck .info-level:focus { outline: 2px solid var(--pd-brand); outline-offset: 1px; }
.prop-deck .info-btn {
  appearance: none;
  background: var(--pd-overlay-soft);
  color: var(--pd-text-secondary);
  border: 1px solid var(--pd-overlay-medium);
  border-radius: var(--mtt-radius-pill);
  padding: 4px 14px;
  font: inherit;
  font-size: 0.78rem;
  font-weight: var(--mtt-fw-medium);
  cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.prop-deck .info-btn:hover {
  background: var(--pd-overlay-medium);
  border-color: var(--pd-overlay-strong);
  color: var(--pd-text-bright);
}
.prop-deck .info-panel {
  margin: 4px 12px 8px;
  padding: 0;
  background: transparent;
  border: 0;
  font-size: var(--mtt-fs-sm);
  line-height: 1.4;
  color: var(--pd-info-text);
}
.prop-deck .info-panel .summary {
  color: var(--pd-info-text-strong);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  /* Cap the visual height as a fallback for engines that don't honor
     -webkit-line-clamp (matches ~3 lines at our line-height of 1.4). */
  max-height: calc(1.4em * 3);
}
.prop-deck .info-panel .summary-read-more {
  display: none;
  margin-top: 4px;
  appearance: none;
  background: transparent;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: 0.78rem;
  color: var(--pd-info-link);
  cursor: pointer;
  text-decoration: underline;
}
.prop-deck .info-panel.has-overflow .summary-read-more { display: inline-block; }
.prop-deck .info-panel .summary-read-more:hover { filter: brightness(1.1); }

/* Summary modal — reuses .prop-deck-modal overlay; wider card + scroll. */
.prop-deck-modal .summary-modal-card {
  max-width: 520px;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
}
.prop-deck-modal .summary-modal-body {
  overflow-y: auto;
  white-space: pre-wrap;
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--pd-text-primary);
  margin: 0 0 18px;
  flex: 1 1 auto;
}
.prop-deck .info-panel .stats {
  margin-top: 6px;
  display: flex; flex-wrap: wrap; gap: 4px;
}
.prop-deck .info-panel .stat-chip {
  background: var(--pd-overlay-soft);
  border: 1px solid var(--pd-overlay-medium);
  border-radius: var(--mtt-radius-pill);
  padding: 2px 8px;
  font-size: var(--mtt-fs-eyebrow);
  color: var(--pd-text-secondary);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.prop-deck .info-panel .sources {
  margin-top: 6px;
  font-size: var(--mtt-fs-eyebrow);
  color: var(--pd-info-meta);
  line-height: 1.4;
}
.prop-deck .info-panel .sources a {
  color: var(--pd-info-link);
  text-decoration: none;
  word-break: break-word;
}
.prop-deck .info-panel .meta {
  margin-top: 4px;
  font-size: 0.68rem;
  color: var(--pd-info-meta);
}
.prop-deck .info-panel.loading { color: var(--pd-info-meta); font-style: italic; }
.prop-deck .info-panel.error { color: var(--pd-info-error-text); }

/* --- Pagination dots --- */
/* Optional progress-dot row rendered when PropDeck.mount is called
   with `showPagination: true`.  Swiper handles wiring the bullets;
   these tokens just tune size + color to match the deck's palette. */
.prop-deck {
  --swiper-pagination-color: var(--pd-brand);
  --swiper-pagination-bullet-inactive-color: var(--pd-text-muted);
  --swiper-pagination-bullet-inactive-opacity: 0.35;
  --swiper-pagination-bullet-size: 6px;
  --swiper-pagination-bullet-horizontal-gap: 4px;
}
.prop-deck .stack > .swiper-pagination {
  /* Pull the indicator out of the Swiper container's absolute-positioned
     bottom (which would land it under the deck on top of the
     `.controls` row) and into the static flow so it sits naturally
     between the deck and the controls.  Same layout works for both
     the legacy bullets and the current fraction renderer. */
  position: static;
  margin-top: 12px;
  display: flex;
  justify-content: center;
  align-items: center;
}
.prop-deck .stack > .swiper-pagination-fraction {
  /* Typography for the "1 / 26" counter — slightly muted, tabular
     digits so the width doesn't twitch as the current index ticks
     past single → double digits while swiping. */
  font-size: 13px;
  font-weight: 600;
  color: var(--pd-text-muted);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}
.prop-deck .stack > .swiper-pagination-fraction .swiper-pagination-current {
  color: var(--pd-text);
}

/* --- Controls + hint --- */
.prop-deck .controls {
  margin-top: 32px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.prop-deck .controls button {
  flex: 1;
  padding: 10px 16px;
  background: var(--pd-surface);
  border: 1px solid var(--pd-border);
  border-radius: var(--mtt-radius-md);
  color: var(--pd-text-primary);
  font-size: 0.9rem;
  cursor: pointer;
  font-family: inherit;
}
.prop-deck .controls button:hover:not(:disabled) { background: var(--pd-surface-hover); }
.prop-deck .controls button:disabled { opacity: 0.4; cursor: not-allowed; }
.prop-deck .progress {
  flex: 0 0 auto;
  font-size: 0.85rem;
  color: var(--pd-text-muted);
  min-width: 56px;
  text-align: center;
}
/* Deck-level "Update" row, sits directly under Prev/Next.  Visible to
   every viewer when the host passes an onRefresh hook to
   PropDeck.mount() — the markup is only rendered in that case (see
   prop-stack.js).  Server-side per-event cooldown on /refresh-odds
   bounds API spend regardless of how many fans click. */
.prop-deck .deck-update {
  margin-top: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 10px;
}
/* Admin-only: the deck-level "↻ Restack pack" button forces a fresh
   Odds API pull and is operational chrome fans don't need.  Same
   .prop-deck--admin toggle as the other admin-only deck controls. */
.prop-deck:not(.prop-deck--admin) .deck-update {
  display: none;
}
.prop-deck .deck-update button {
  appearance: none;
  font: inherit;
  font-weight: var(--mtt-fw-medium);
  background: var(--pd-overlay-soft);
  color: var(--pd-text-secondary);
  border: 1px solid var(--pd-overlay-medium);
  border-radius: var(--mtt-radius-pill);
  padding: 6px 16px;
  cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.prop-deck .deck-update button:hover:not(:disabled) {
  background: var(--pd-overlay-medium);
  border-color: var(--pd-overlay-strong);
  color: var(--pd-text-bright);
}
.prop-deck .deck-update button:disabled { cursor: default; opacity: 0.6; }
.prop-deck .deck-update button.is-loading { opacity: 0.85; }
.prop-deck .deck-update-status {
  font-size: 0.78rem;
  color: var(--pd-text-muted);
}

.prop-deck .hint {
  margin-top: 24px;
  text-align: center;
  font-size: 0.78rem;
  color: var(--pd-text-faint);
}
.prop-deck .empty,
.prop-deck .loading {
  text-align: center;
  color: var(--pd-text-faint);
  padding: 48px 20px;
  font-size: 0.9rem;
}

/* "Change your take?" confirmation modal.  Lives outside .prop-deck
   because it's appended to <body> for proper stacking — kept in this
   stylesheet so the styling ships alongside the component. */
.prop-deck-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  animation: prop-deck-modal-fade-in 120ms ease-out;
}
@keyframes prop-deck-modal-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.prop-deck-modal-card {
  width: 100%;
  max-width: 380px;
  background: var(--mtt-surface-panel);
  border: 1px solid color-mix(in srgb, var(--mtt-overlay) 12%, transparent);
  border-radius: var(--mtt-radius-2xl);
  padding: 22px;
  color: var(--mtt-text-bright);
  font-family: inherit;
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.4);
}
.prop-deck-modal-card h3 {
  margin: 0 0 8px;
  font-size: 1.1rem;
  font-weight: var(--mtt-fw-semibold);
  color: var(--mtt-text-display);
}
.prop-deck-modal-card p {
  margin: 0 0 18px;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--mtt-text-secondary);
}
.prop-deck-modal-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  flex-wrap: wrap;
}
.prop-deck-modal-actions .modal-btn {
  appearance: none;
  font: inherit;
  font-size: var(--mtt-fs-base);
  font-weight: var(--mtt-fw-semibold);
  padding: 9px 16px;
  border-radius: var(--mtt-radius-md);
  cursor: pointer;
  border: 1px solid transparent;
  transition: background 0.15s, border-color 0.15s, opacity 0.15s;
}
.prop-deck-modal-actions .modal-btn-secondary {
  background: transparent;
  color: var(--mtt-text-secondary);
  border-color: var(--pd-border);
}
.prop-deck-modal-actions .modal-btn-secondary:hover {
  background: color-mix(in srgb, var(--mtt-overlay) 4%, transparent);
  border-color: #3a4049;
}
.prop-deck-modal-actions .modal-btn-primary {
  background: var(--mtt-brand-500);
  color: var(--mtt-surface-base);
}
.prop-deck-modal-actions .modal-btn-primary:hover:not([disabled]) {
  background: var(--mtt-brand-400);
}
.prop-deck-modal-actions .modal-btn[disabled] {
  opacity: 0.6;
  cursor: progress;
}
.market-closed-replacement-preview {
  margin: 12px 0 18px;
  padding: 14px;
  border-radius: var(--mtt-radius-lg);
  background: color-mix(in srgb, var(--mtt-brand-500) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--mtt-brand-500) 32%, transparent);
}
.market-closed-replacement-preview__question {
  font-size: 0.92rem;
  font-weight: var(--mtt-fw-semibold);
  color: var(--mtt-text-display);
  margin-bottom: 10px;
  line-height: 1.35;
}
.market-closed-replacement-preview__sides {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}
.market-closed-replacement-preview__side {
  flex: 1 1 0;
  min-width: 110px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px 10px;
  border-radius: var(--mtt-radius-md);
  background: color-mix(in srgb, var(--mtt-overlay) 12%, transparent);
}
.market-closed-replacement-preview__label {
  font-size: 0.82rem;
  color: var(--mtt-text-secondary);
  line-height: 1.2;
}
.market-closed-replacement-preview__odds {
  font-size: 0.95rem;
  font-weight: var(--mtt-fw-semibold);
  color: var(--mtt-text-bright);
}
.market-closed-note {
  font-size: 0.82rem !important;
  color: var(--mtt-text-muted, #9aa0a6) !important;
  margin-bottom: 0 !important;
  font-style: italic;
}
