/* ---------------------------------------------------------------------------
   MTG Mock Draft — "The Draft Table"
   Design tokens for a dusk-lit draft table:
   a dusk-indigo table surface (card art pops on dark), moonlight-parchment
   ink, warm gold for scores and primary actions, and the five mana colors
   as *functional* tokens (the lane meter — the signature element — encodes
   live color power in WUBRG bands).
   Type: Fraunces (display, used sparingly) / IBM Plex Sans (UI) /
   IBM Plex Mono (every number: scores, lane power, badges).

   Viewport bands: app.js's MQ map is the source of truth for every "is this a
   phone?" query, and each band's media queries below are tagged with the MQ.*
   name they mirror — grep either name to find both halves. Keep a tagged query
   byte-identical to its MQ entry; if a band needs to change, change it there
   first. Untagged @media rules are ordinary responsive breakpoints with no JS
   counterpart, and are free to move on their own.
   --------------------------------------------------------------------------- */

:root {
  --bg: #131120;          /* table dusk */
  --bg-deep: #0e0c1a;
  --panel: #1c1930;       /* table panel */
  --panel-2: #242040;     /* raised surface: inputs, chips */
  --ink: #ece7db;         /* moonlight parchment */
  --muted: #a49bb4;
  --line: #322d4d;        /* hairline */
  --line-soft: #282344;
  --gold: #d9ab4a;        /* warm gold */
  --gold-soft: #e8c87e;
  --gold-deep: #8f6c1e;
  --danger: #e0685a;
  /* True-to-pie mana colors. Black is genuinely dark — it gets a pale inner
     edge on its band so it reads against the track (see .lane-band rules). */
  --mana-w: #f7f1cf;
  --mana-u: #2f7fe0;
  --mana-b: #4c4058;
  --mana-r: #d93a2b;
  --mana-g: #2f9e4f;
  --font-display: "Fraunces", "Georgia", serif;
  --font-body: "IBM Plex Sans", "Segoe UI", sans-serif;
  --font-mono: "IBM Plex Mono", "SF Mono", monospace;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  background-color: var(--bg);
  /* Gold halo cresting the top of the table. */
  background-image: radial-gradient(1100px 520px at 50% -260px, #2a2450 0%, rgba(42, 36, 80, 0) 70%);
  background-repeat: no-repeat;
}

/* ---- Type scale -------------------------------------------------------- */

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  white-space: nowrap;
  text-decoration: none;
  color: inherit;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.brand-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.brand-kicker {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 0.56rem;
  letter-spacing: 0.34em;
  color: var(--gold);
  line-height: 1;
}

.brand-name {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 600;
  font-size: 1.22rem;
  letter-spacing: 0.01em;
  color: var(--ink);
  line-height: 1.1;
}

/* Panel headings are quiet structural eyebrows, not display type. */
h2 {
  margin: 0 0 8px;
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

/* The brand logo: the WUBRG "Pick Compass". */
.brand-logo {
  width: 30px;
  height: 30px;
  flex: none;
  filter: drop-shadow(0 0 8px rgba(217, 171, 74, 0.28));
}

/* ---- Top bar ------------------------------------------------------------ */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Always allow wrapping: if the row ever exceeds the viewport (long set name,
     narrow window), the action group drops to a second line instead of being
     cut off the right edge. The media query below drops the lane panel first
     for a tidier layout, but this is the hard guarantee nothing clips. */
  flex-wrap: wrap;
  row-gap: 8px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--line);
  background: rgba(19, 17, 32, 0.92);
  backdrop-filter: blur(8px);
  position: sticky;
  top: 0;
  z-index: 30000;
}

.top-actions { display: flex; gap: 8px; }
.info-actions { display: flex; gap: 8px; margin-left: 16px; }

/* ---- Lane panel — the signature element --------------------------------- */

.lane-panel {
  margin-left: auto;
  margin-right: 12px;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg-deep);
  /* Shrinkable so it stays on the top row when space is tight: the meter (left)
     stays put and the numeric readout (right) clips, rather than the panel
     dropping to its own row. */
  min-width: 0;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 12px;
}

.lane-meter {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 34px;
  flex: none;
}

.lane-band {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  width: 16px;
  height: 100%;
}

.lane-band i {
  flex: 1;
  width: 100%;
  border-radius: 3px;
  background:
    linear-gradient(to top, var(--band-color, var(--muted)) calc(var(--fill, 0) * 100%), transparent calc(var(--fill, 0) * 100%)),
    var(--line-soft);
  opacity: 0.45;
  transition: opacity 200ms ease;
}

.lane-band b {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 0.56rem;
  color: var(--muted);
  line-height: 1;
}

.lane-band[data-c="W"] { --band-color: var(--mana-w); }
.lane-band[data-c="U"] { --band-color: var(--mana-u); }
.lane-band[data-c="B"] { --band-color: var(--mana-b); }
.lane-band[data-c="R"] { --band-color: var(--mana-r); }
.lane-band[data-c="G"] { --band-color: var(--mana-g); }

/* Black mana is nearly the color of the table — give its band a pale inner
   edge so a black lane is unmistakable. */
.lane-band[data-c="B"] i {
  box-shadow: inset 0 0 0 1px rgba(236, 231, 219, 0.22);
}

.lane-band.in-lane i { opacity: 1; box-shadow: 0 0 8px rgba(217, 171, 74, 0.25); }
.lane-band.in-lane b { color: var(--ink); }

.lane-text { min-width: 0; }

.lane-colors {
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--ink);
  margin-bottom: 2px;
}

.lane-power {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--muted);
  white-space: nowrap;
}

/* A lane pair exists but isn't established yet (laneReady false from the
   backend): dim the meter and mute the label so the UI doesn't assert a lane
   the engine isn't acting on. */
.lane-meter.forming { opacity: 0.55; }
.lane-colors.forming { color: var(--muted); font-weight: 600; }

/* ---- Buttons: one gold primary, everything else quiet ------------------- */

button {
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--ink);
  border-radius: 8px;
  padding: 8px 12px;
  cursor: pointer;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.86rem;
  white-space: nowrap;
}

button:hover { border-color: var(--gold); }

button:focus-visible,
select:focus-visible,
.card:focus-visible,
.deck-stack-card:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* Primary action: start the draft. */
#start-btn,
#feedback-send-btn,
.set-select-list button {
  background: var(--gold);
  border: 1px solid var(--gold-deep);
  color: #171126;
  font-weight: 700;
}

#start-btn:hover,
#feedback-send-btn:hover,
.set-select-list button:hover {
  background: var(--gold-soft);
  border-color: var(--gold-deep);
}

/* ---- Layout ------------------------------------------------------------- */

.layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 16px;
  padding: 16px;
}

/* Site footer — shared attribution + links, mirrored from landing.css so it
   renders on the draft app too (index.html loads only styles.css). */
.site-footer {
  border-top: 1px solid var(--line);
  margin-top: 8px;
  padding: 26px 16px;
  color: var(--muted);
  font-size: 0.8rem;
}
.site-footer .wrap {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}
.footer-links { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.footer-link {
  font: inherit;
  color: var(--muted);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color 140ms ease;
}
.footer-link:hover { color: var(--ink); }
.footer-socials { display: inline-flex; align-items: center; gap: 14px; }
.footer-social {
  color: var(--muted);
  display: inline-flex;
  transition: color 140ms ease, transform 140ms ease;
}
.footer-social:hover { color: var(--gold); transform: translateY(-1px); }
.footer-social svg { display: block; }

.main-panel, .side-panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 12px;
}

/* Drag-to-draft: a pack card dragged over "Your Picks" highlights the panel. */
.side-panel.drag-over {
  border-color: var(--gold-deep);
  box-shadow: inset 0 0 0 2px var(--gold-deep);
}
.card.dragging { opacity: 0.5; }

.status-row {
  margin-bottom: 12px;
  color: var(--muted);
  font-weight: 600;
  font-size: 0.9rem;
}

/* ---- Pack grid ----------------------------------------------------------- */

.pack-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 12px;
}

.card {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 0;
  overflow: hidden;
  background: var(--bg-deep);
  text-align: left;
  position: relative;
  transition: transform 120ms ease, border-color 120ms ease, box-shadow 120ms ease;
  /* Rapid tap-to-preview / tap-to-pick flow: no 300ms delay, no grey tap flash. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.card:hover {
  transform: translateY(-2px);
  border-color: var(--gold-deep);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.45);
}

.card-image {
  width: 100%;
  display: block;
  aspect-ratio: 5/7;
  object-fit: cover;
  background: var(--panel-2);
  transition: transform 120ms ease;
  transform-style: preserve-3d;
}

.card-image.flipped {
  transform: none;
}

.rating-badge {
  position: absolute;
  top: 30px;
  left: 8px;
  background: rgba(10, 8, 20, 0.9);
  color: var(--gold-soft);
  border: 1px solid rgba(217, 171, 74, 0.4);
  border-radius: 999px;
  padding: 3px 8px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  z-index: 3;
  pointer-events: none;
}

.card-meta {
  display: block;
  padding: 8px;
  font-size: 0.76rem;
  line-height: 1.4;
  color: var(--muted);
  white-space: pre-line;
}

/* ---- Picks sidebar ------------------------------------------------------- */

#pick-count {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--muted);
  margin-bottom: 8px;
}

#pick-list {
  margin: 0;
  padding-left: 20px;
  max-height: 75vh;
  overflow: auto;
}

#pick-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 0 0 6px;
  font-size: 0.88rem;
  cursor: default;
}

#pick-list li::marker {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--muted);
}

#pick-list li.ignored-pick {
  color: #9088a6;
  text-decoration: line-through;
}

#pick-list li:focus {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
  border-radius: 4px;
}

.pick-item-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1 1 auto;
}

/* Mana-cost pips to the left of each pick's name. The column is a FIXED width
   (not min-width) so its right edge never moves: every card name starts at the
   same x and the rightmost pips line up across rows regardless of cost length.
   54px fits 4 pips; the rare 5-pip cost overflows harmlessly to the left. */
.pick-pips {
  display: inline-flex;
  align-items: center;
  /* Right-align so the rightmost pip sits flush against the name and stays on
     the fixed right edge; extra pips spill left instead of pushing the name. */
  justify-content: flex-end;
  gap: 2px;
  flex: none;
  width: 54px;
}
.pip {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 0.55rem;
  font-weight: 700;
  border: 1px solid rgba(236, 231, 219, 0.25);
}
/* Official mana-symbol SVGs (ui/mana/) — the artwork carries its own circle. */
.pip-img { border: none; background: none; }
.pip-generic { background: var(--panel-2); color: var(--ink); }

/* Cumulative-total badge (fix #3), same pill treatment as the deck-stack badge,
   tinted by applyRatingColor to match the on-card badge tiers. */
.pick-item-badge {
  flex: 0 0 auto;
  background: rgba(10, 8, 20, 0.88);
  border: 1px solid rgba(217, 171, 74, 0.35);
  border-radius: 999px;
  padding: 1px 6px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
}

.pick-preview {
  position: sticky;
  bottom: 8px;
  margin-top: 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg-deep);
  padding: 8px;
  display: none;
}

.pick-preview.visible {
  display: block;
}

.pick-preview img {
  width: 100%;
  display: block;
  border-radius: 8px;
  background: var(--panel-2);
  aspect-ratio: 5 / 7;
  object-fit: cover;
}

.pick-preview-name {
  margin-top: 8px;
  font-size: 0.85rem;
  color: var(--muted);
}

/* ---- Score scorecard popover ---------------------------------------------- */
/* A floating pick-score card anchored beside the hovered card (draft pack, pick
   list, and deckbuilder stacks). Echoes the landing hero's score panel, built
   from the app's own tokens. Sits above the card-zoom image (z 10000). */

.scorecard {
  position: fixed;
  z-index: 10001;
  width: 300px;
  max-width: calc(100vw - 16px);
  background: linear-gradient(180deg, var(--panel), var(--bg-deep));
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 16px;
  box-shadow: 0 24px 60px -24px rgba(0, 0, 0, 0.85);
  pointer-events: auto;
  display: none;
  font-family: var(--font-body);
}

.scorecard.visible {
  display: block;
  animation: sc-in 140ms ease both;
}

@keyframes sc-in {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

/* Mobile/narrow: the scorecard docks as a bottom sheet (set by
   isMobileScorecard() in app.js) instead of floating beside the tapped card,
   so it never blankets the pack grid. Capped height + its own scroll keep the
   grid above the fold reachable; the tapped card is scrolled to the top of
   the viewport (see showScorecardAt) so the fold never lands on its row. The
   top handle bar is a tray-lip affordance, echoing a card being slid across
   the table rather than a generic modal. */
.scorecard.sheet {
  left: 0;
  right: 0;
  bottom: 0;
  top: auto;
  width: 100%;
  max-width: 100%;
  max-height: min(62vh, 560px);
  overflow-y: auto;
  overscroll-behavior: contain;
  border-radius: 18px 18px 0 0;
  border-bottom: none;
  padding: 8px 18px calc(18px + env(safe-area-inset-bottom, 0px));
  box-shadow: 0 -20px 50px -16px rgba(0, 0, 0, 0.85);
}

.scorecard.sheet::before {
  content: "";
  display: block;
  width: 36px;
  height: 4px;
  margin: 2px auto 14px;
  border-radius: 3px;
  background: var(--gold-soft);
  opacity: 0.55;
  /* Tapping the handle strip dismisses the sheet (see SHEET_HANDLE_HIT_PX in
     app.js), so it has to read as clickable. */
  cursor: pointer;
}

.scorecard.sheet.visible {
  animation: sc-sheet-in 220ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* Collapsed pack sheet: header + pager + Pick button only. The summary bars
   and lane strip stay behind the "Full breakdown" toggle (sc-expanded),
   keeping the sheet short so it covers less of the pack grid. Applies to the
   docked sheet only; desktop popovers keep the always-visible summary. */
.scorecard.sheet.sc-pack-mode:not(.sc-expanded) > .sc-rows:not(.sc-details),
.scorecard.sheet.sc-pack-mode:not(.sc-expanded) > .sc-lane {
  display: none;
}

/* Zero-value terms are noise at phone height; the expanded breakdown lists
   only the terms actually contributing. Desktop popovers keep the full list. */
.scorecard.sheet .sc-details .sc-row-zero {
  display: none;
}

.sc-details .sc-zero-note {
  display: none;
}
.scorecard.sheet .sc-details .sc-zero-note {
  display: block;
  color: var(--muted, #8b8fa3);
  font-size: 0.8rem;
  padding: 4px 0 2px;
}

@keyframes sc-sheet-in {
  from { opacity: 0; transform: translateY(100%); }
  to { opacity: 1; transform: translateY(0); }
}

.sc-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line-soft);
  margin-bottom: 12px;
}

.sc-cardname { font-weight: 700; font-size: 0.98rem; line-height: 1.2; }
.sc-cardname-row { display: flex; align-items: center; gap: 8px; }
/* Tap-to-zoom affordance, mobile pack sheet only (see showZoom in
   scorecardHeaderHtml). Carries a labelled pill rather than a bare glyph: an
   unlabelled icon next to the card name reads as decoration, and this is the
   only way to read card text on a phone, so it has to announce itself. Height
   is 36px with the row's padding giving the rest of the 44px tap target. */
.sc-zoom-btn {
  flex: none;
  height: 36px;
  padding: 0 12px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1;
  cursor: pointer;
}
.sc-zoom-btn .sc-zoom-glyph { font-size: 0.85rem; line-height: 1; }
.sc-zoom-btn:hover,
.sc-zoom-btn:focus-visible { border-color: var(--gold); color: var(--gold); }
.sc-cardmeta {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  color: var(--muted);
  margin-top: 3px;
}
.sc-score {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 1.9rem;
  line-height: 1;
  color: var(--gold);
  text-align: right;
  white-space: nowrap;
}
.sc-score small {
  display: block;
  font-size: 0.46rem;
  letter-spacing: 0.22em;
  color: var(--muted);
  margin-top: 5px;
}
.sc-score-delta { font-size: 1.6rem; color: var(--gold-soft); }

.sc-rows { display: flex; flex-direction: column; gap: 8px; }
.sc-row {
  display: grid;
  grid-template-columns: 92px 1fr auto;
  align-items: center;
  gap: 9px;
}
.sc-label {
  font-size: 0.7rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sc-bar {
  height: 6px;
  border-radius: 4px;
  background: var(--line-soft);
  overflow: hidden;
}
.sc-bar > i {
  display: block;
  height: 100%;
  border-radius: 4px;
  width: var(--w, 40%);
  background: var(--c, var(--gold));
  transform-origin: left;
  animation: sc-fill 700ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes sc-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.sc-val { font-family: var(--font-mono); font-size: 0.72rem; color: var(--ink); }

/* One-line empirical stats (GD WR · IWD) under the Base bar — numbers, no bars. */
.sc-statline {
  display: flex;
  align-items: baseline;
  gap: 6px 8px;
}
.sc-statline .sc-label { flex: none; }
.sc-statline .sc-val { margin-right: 10px; }

/* A labeled divider between bar groups (e.g. Base Rating vs Deck-Context),
   used in both the normal scorecard's bar view and the swap-delta view. */
.sc-row-section {
  font-weight: 700;
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold);
  margin-top: 4px;
}

/* Center-origin diverging bar for delta values (swap preview, fix #2): negative
   grows left from the midline, positive grows right, magnitude-scaled and
   capped at half the track so the two sides never overrun each other. */
.sc-bar-diverge {
  position: relative;
  height: 6px;
  border-radius: 4px;
  background: var(--line-soft);
}
.sc-bar-diverge::after {
  content: "";
  position: absolute;
  left: 50%;
  top: -2px;
  bottom: -2px;
  width: 1px;
  background: var(--line);
}
.sc-bar-diverge-fill {
  position: absolute;
  top: 0;
  height: 100%;
  width: var(--w, 0%);
  background: var(--c, var(--mana-g));
  animation: sc-fill-diverge 700ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
.sc-bar-diverge-pos { left: 50%; border-radius: 0 4px 4px 0; transform-origin: left; }
.sc-bar-diverge-neg { right: 50%; border-radius: 4px 0 0 4px; transform-origin: right; }
@keyframes sc-fill-diverge { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.sc-row-total .sc-label,
.sc-row-total .sc-val { font-weight: 700; }
.sc-row-total .sc-bar-diverge { height: 8px; }

/* Swap-delta labels ("Deck-Context Total", "Context Shift (other cards)")
   run longer than the normal bar view's, give them more room before eliding. */
.sc-row-diverge { grid-template-columns: 136px 1fr auto; }

.sc-rows-open { margin-top: 4px; }

.sc-lane {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 26px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
}
.sc-band {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  width: 16px;
  height: 100%;
}
.sc-band i {
  flex: 1;
  width: 100%;
  border-radius: 3px;
  background: var(--line-soft);
  opacity: 0.6;
}
.sc-band b {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 0.52rem;
  color: var(--muted);
  line-height: 1;
}
.sc-band.on[data-c="W"] i { background: var(--mana-w); }
.sc-band.on[data-c="U"] i { background: var(--mana-u); }
.sc-band.on[data-c="B"] i { background: var(--mana-b); box-shadow: inset 0 0 0 1px rgba(236, 231, 219, 0.22); }
.sc-band.on[data-c="R"] i { background: var(--mana-r); }
.sc-band.on[data-c="G"] i { background: var(--mana-g); }
.sc-band.on i { opacity: 1; }
.sc-band.on b { color: var(--ink); }

.sc-expand {
  width: 100%;
  margin-top: 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 7px 10px;
  border-radius: 8px;
  cursor: pointer;
}
.sc-expand:hover { border-color: var(--gold); color: var(--ink); }
.sc-expand-caret { transition: transform 140ms ease; }
.sc-expand[aria-expanded="true"] .sc-expand-caret { transform: rotate(90deg); }

.sc-details { margin: 10px 0 0; }
.sc-details[hidden] { display: none; }

/* ---- Mobile pack sheet: prev/next chevrons + explicit pick button (see
   scorecardPackActionsHtml / stepPackScorecard in app.js). Only ever
   rendered while the sheet is docked (isMobileScorecard()) and anchored to a
   pack card, so these never appear on desktop or off the draft screen. ---- */
.sc-pack-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-bottom: 10px;
}

.sc-nav-btn {
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--ink);
  font-size: 1.3rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
.sc-nav-btn:hover,
.sc-nav-btn:focus-visible { border-color: var(--gold); color: var(--gold); }
.sc-nav-btn:disabled { opacity: 0.35; pointer-events: none; }

.sc-pack-pos {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--muted);
  min-width: 52px;
  text-align: center;
}

.sc-pick-btn {
  display: block;
  width: 100%;
  padding: 12px 14px;
  margin-bottom: 12px;
  background: var(--gold);
  border: 1px solid var(--gold-deep);
  border-radius: 10px;
  color: var(--bg-deep);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.92rem;
}
.sc-pick-btn:hover,
.sc-pick-btn:focus-visible { background: var(--gold-soft); }

/* Anchor tile for the currently-shown pack sheet, kept in sync as the sheet
   pages through the pack (stepPackScorecard). */
.card.pack-card-active {
  border-color: var(--gold);
  box-shadow: 0 0 0 2px var(--gold-deep);
}

/* ---- Compact pack tile labels (art-crop grid on phones) — built for every
   pack card in app.js, desktop just never shows it (same convention as
   .deck-stack-mobile-info). ---- */
.pack-card-mobile-info { display: none; }

/* ---- Rotate-for-landscape hint toast (one-time, see maybeShowRotateHint) ---- */
.rotate-hint-toast {
  position: fixed;
  left: 50%;
  bottom: max(20px, env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 10010;
  background: linear-gradient(180deg, var(--panel), var(--bg-deep));
  border: 1px solid var(--gold-deep);
  color: var(--ink);
  padding: 10px 16px;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 600;
  box-shadow: 0 16px 40px -16px rgba(0, 0, 0, 0.8);
  animation: rotate-hint-in 200ms ease both;
}
.rotate-hint-toast--out {
  animation: rotate-hint-out 200ms ease both;
}
@keyframes rotate-hint-in {
  from { opacity: 0; transform: translateX(-50%) translateY(10px); }
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
@keyframes rotate-hint-out {
  from { opacity: 1; }
  to { opacity: 0; transform: translateX(-50%) translateY(10px); }
}

/* ---- Final deck ------------------------------------------------------------ */

.final-deck {
  margin-top: 12px;
  border-top: 1px solid var(--line);
  padding-top: 10px;
}

.final-deck[hidden] {
  display: none;
}

.final-deck-summary {
  font-size: 0.85rem;
  color: var(--muted);
  margin-bottom: 8px;
}

.final-deck-block {
  margin-bottom: 8px;
  font-size: 0.85rem;
}

.final-deck-block h3 {
  margin: 0 0 4px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.final-deck-block ol,
.final-deck-block ul {
  margin: 0;
  padding-left: 18px;
}

.final-deck-block li {
  margin-bottom: 3px;
}

/* ---- Deckbuilder ------------------------------------------------------------ */

.deckbuilder-view {
  padding: 16px;
}

.deckbuilder-view[hidden] {
  display: none;
}

.deckbuilder-toolbar {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 12px;
  margin-bottom: 6px;
  flex-wrap: nowrap;
}

.deckbuilder-toolbar h2 {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--ink);
  margin: 0;
}

.deckbuilder-summary {
  flex: 1 1 100%;
  color: var(--muted);
  font-size: 0.78rem;
  line-height: 1.4;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--line-soft);
}

/* ---- Final Deck panel (live in-app version of the landing "built-deck"
   panel) — reuses the same tokens (--panel, --gold, --mana-*) but lays out
   compactly as one horizontal strip since the deckbuilder workspace is
   already dense with the bench/maindeck grids below it. */

.final-deck-panel {
  display: flex;
  align-items: stretch;
  flex-wrap: wrap;
  gap: 18px;
  background: linear-gradient(180deg, var(--panel), var(--bg-deep));
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 14px 16px;
  margin-bottom: 12px;
}

/* A <button> so the phone breakpoint can use it as the summary's collapse
   toggle (see the max-width:700px block); everything here strips the button
   chrome back to the plain header it was, and desktop leaves it inert. */
.fdp-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  flex: 1 1 220px;
  min-width: 200px;
  padding: 0 16px 0 0;
  border: none;
  border-right: 1px solid var(--line-soft);
  border-radius: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: default;
}

.fdp-head:hover { background: none; }

/* Collapse affordance: phone-only (see the max-width:700px block). */
.fdp-toggle-chevron {
  display: none;
  flex: none;
  align-self: center;
  color: var(--muted);
  transition: transform 140ms ease;
}

.fdp-head-text { min-width: 0; }

.fdp-title { font-weight: 700; font-size: 0.95rem; color: var(--ink); }

.fdp-meta {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--muted);
  margin-top: 3px;
}

.fdp-count {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 1.7rem;
  line-height: 1;
  color: var(--gold);
  text-align: right;
  flex: none;
}

.fdp-count small {
  display: block;
  font-size: 0.48rem;
  letter-spacing: 0.2em;
  color: var(--muted);
  margin-top: 4px;
}

.fdp-curve {
  flex: 1 1 200px;
  min-width: 180px;
  padding-right: 16px;
  border-right: 1px solid var(--line-soft);
}

.fdp-curve-label {
  font-family: var(--font-mono);
  font-size: 0.58rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 8px;
}

.fdp-curve-bars {
  display: flex;
  align-items: flex-end;
  gap: 5px;
  height: 38px;
}

.fdp-bar {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  height: 100%;
}

.fdp-bar i {
  flex: 1;
  width: 100%;
  border-radius: 3px 3px 2px 2px;
  background: linear-gradient(to top, var(--gold) calc(var(--f, 0) * 100%), var(--line-soft) calc(var(--f, 0) * 100%));
}

.fdp-bar b {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 0.54rem;
  color: var(--muted);
  line-height: 1;
}

.fdp-mana {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  flex: 1 1 180px;
  min-width: 160px;
  padding-right: 16px;
  border-right: 1px solid var(--line-soft);
}

.fdp-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--ink);
}
.fdp-chip i { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.fdp-chip[data-c="W"] i { background: var(--mana-w); box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.28); }
.fdp-chip[data-c="U"] i { background: var(--mana-u); }
.fdp-chip[data-c="B"] i { background: var(--mana-b); box-shadow: inset 0 0 0 1px rgba(236, 231, 219, 0.22); }
.fdp-chip[data-c="R"] i { background: var(--mana-r); }
.fdp-chip[data-c="G"] i { background: var(--mana-g); }
.fdp-chip-note { font-family: var(--font-mono); font-size: 0.66rem; color: var(--muted); }

.fdp-stats {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px 18px;
  flex: 1 1 200px;
  min-width: 180px;
}

.fdp-stat { display: flex; flex-direction: column; gap: 2px; }
.fdp-stat b { font-family: var(--font-mono); font-weight: 700; font-size: 1rem; color: var(--gold-soft); }
.fdp-stat span {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.fdp-castability {
  flex: 1 1 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding-top: 12px;
  border-top: 1px solid var(--line-soft);
}
.fdp-castability b {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 1rem;
  color: var(--mana-g);
  flex: none;
}
.fdp-castability span {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  color: var(--muted);
}

/* ---- Deckbuilder pool filter bar (mirrors the tier list's filter bar in
   ui/tierlist.css: same class names/shape so the two stay visually
   identical; duplicated here rather than shared because there is no
   build step to import a common module from). Filters the "Drafted But
   Not In Deck" bench pool only; the built maindeck always stays fully
   shown, since it's the thing you're actively reviewing/swapping. ---- */

/* Mobile-only "Filters" toggle (see the max-width:700px block below); the
   filter bar itself is always visible on desktop, so this stays hidden there. */
.filter-toggle-btn { display: none; }

/* Mobile-only name/mana text on deck-stack cards (see app.js
   createDeckStackCardNode + the max-width:700px block below); the desktop
   mini-card presentation reads name/cost off the card art itself. */
.deck-stack-mobile-info,
.deck-stack-name-mobile--basic { display: none; }

/* Touch-only one-tap move control on every spell row (see app.js
   createDeckStackCardNode). Desktop moves cards by dragging them between the
   bench and the deck, so this stays hidden there. */
.deck-stack-move-btn { display: none; }

.deckbuilder-filter-bar {
  --rarity-common: var(--muted);
  --rarity-uncommon: #c7c2d6;
  --rarity-rare: var(--gold);
  --rarity-mythic: #ff7a42;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 18px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 12px;
}

.filter-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.filter-search { flex: 1 1 200px; min-width: 160px; }

.filter-label {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.filter-input,
.filter-select {
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--ink);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 0.86rem;
  font-family: inherit;
  height: 36px;
}

.filter-input:focus-visible,
.filter-select:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 1px;
}

.filter-input::placeholder { color: var(--muted); }

.chip-row { display: flex; flex-wrap: wrap; gap: 6px; }

.chip {
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--ink);
  border-radius: 8px;
  height: 36px;
  min-width: 36px;
  padding: 0 10px;
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 0.78rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.chip:hover { border-color: var(--gold); }

.chip:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

.chip[aria-pressed="true"] {
  background: var(--gold);
  border-color: var(--gold-deep);
  color: #171126;
}

.chip-color { width: 40px; padding: 0; }
.chip-color .chip-swatch {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 1px solid rgba(236, 231, 219, 0.35);
}
.chip-color .chip-pip { width: 18px; height: 18px; display: block; }
.chip-color[data-c="M"] .chip-swatch {
  background: linear-gradient(135deg, #e8c87e, #d9ab4a);
  border-color: var(--gold-deep);
}
.chip-color[aria-pressed="true"] { background: var(--panel-2); border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold); }
.chip-color[aria-pressed="true"] .chip-swatch { box-shadow: 0 0 8px rgba(217, 171, 74, 0.6); }
.chip-color[aria-pressed="true"] .chip-pip { filter: drop-shadow(0 0 4px rgba(217, 171, 74, 0.85)); }

.chip-rarity .chip-swatch {
  width: 12px;
  height: 12px;
  border-radius: 50%;
}
.chip-rarity[data-r="common"] .chip-swatch { background: var(--rarity-common); }
.chip-rarity[data-r="uncommon"] .chip-swatch { background: var(--rarity-uncommon); }
.chip-rarity[data-r="rare"] .chip-swatch { background: var(--rarity-rare); }
.chip-rarity[data-r="mythic"] .chip-swatch { background: var(--rarity-mythic); }

.chip-cmc { width: 34px; padding: 0; }

.db-filter-count {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--muted);
  align-self: center;
  min-width: 6em;
}

.filter-reset {
  align-self: flex-end;
  height: 36px;
  background: transparent;
  border: 1px solid var(--line);
  color: var(--muted);
  border-radius: 8px;
  padding: 0 12px;
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
}
.filter-reset:hover { border-color: var(--gold); color: var(--ink); }

/* Cards the current filters exclude from the bench pool. */
.deck-stack-card.pool-card-hidden { display: none; }

@media (pointer: coarse) {
  .deckbuilder-filter-bar .chip { height: 44px; min-width: 44px; }
  .deckbuilder-filter-bar .chip-color { width: 44px; }
  .deckbuilder-filter-bar .chip-cmc { width: 44px; }
}

.deckbuilder-panels {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto auto;
  gap: 12px;
  min-height: 0;
  overflow: visible;
}

.deckbuilder-panel {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  padding: 10px;
  min-width: 0;
  overflow: visible;
}

.deckbuilder-panel h3 {
  margin: 0 0 8px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.deck-panel-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}

.deck-panel-heading h3 {
  margin: 0;
}

#deck-sort-toggle-btn {
  padding: 6px 10px;
  font-size: 0.8rem;
}

/* ---- Card stacks (geometry preserved — JS depends on it) -------------------- */

.stack-row {
  display: flex;
  align-items: flex-end;
  overflow-x: auto;
  overflow-y: hidden;
  padding: 8px 8px 10px 8px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg-deep);
  margin-bottom: 8px;
}

.deckbuilder-panel .stack-row:last-child {
  margin-bottom: 0;
}

#deckbuilder-bench.stack-row {
  display: grid;
  grid-template-columns: repeat(10, 120px);
  grid-auto-rows: 168px;
  grid-auto-flow: row;
  gap: 8px;
  align-items: start;
  align-content: start;
  justify-content: start;
  overflow-x: hidden;
  overflow-y: auto;
  min-height: 372px;
  max-height: 372px;
}

.deck-stack-card {
  position: relative;
  width: 132px;
  aspect-ratio: 5/7;
  border: none;
  border-radius: 8px;
  background: transparent;
  overflow: hidden;
  margin-left: -78px;
  transition: transform 120ms ease, box-shadow 120ms ease;
  z-index: var(--stack-z, 1);
  transform-origin: top center;
  padding: 0;
}

.deck-stack-card:first-child {
  margin-left: 0;
}

.deck-stack-card:hover,
.deck-stack-card:focus {
  transform: translateY(-52px) scale(1.48);
  z-index: 9999 !important;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.55);
}

/* Hover-flicker fix: a bench-card hover rebuilds the whole stack DOM (to show
   the swap-delta preview, see runPointerActivation in app.js), which replaces
   the hovered node with a fresh one. The fresh node briefly renders un-grown
   before the browser re-matches :hover and animates it back up, i.e. a
   grow-shrink-grow flicker. app.js tags the still-hovered card's freshly
   built node with this class so it mounts already enlarged, transition-free,
   instead of replaying the grow animation. */
.deck-stack-card.deck-stack-card--hover-held {
  transition: none !important;
  transform: translateY(-52px) scale(1.48) !important;
  z-index: 9999 !important;
  box-shadow: 0 12px 28px rgba(0, 0, 0, 0.55) !important;
}

/* In-deck stacks: keep card in place; use side zoom preview instead. */
.cmc-stack .deck-stack-card:hover,
.cmc-stack .deck-stack-card:focus {
  transform: none;
  box-shadow: none;
  z-index: var(--stack-z, 1) !important;
}

.deck-stack-card img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

.deck-stack-card.ignored-card {
  filter: grayscale(1) brightness(0.65);
  opacity: 0.95;
}

.deck-stack-card.swap-armed-card {
  outline: 3px solid var(--danger);
  outline-offset: 1px;
  box-shadow: 0 0 0 2px rgba(224, 104, 90, 0.3);
}

.deck-stack-ignored-label {
  position: absolute;
  left: -18px;
  right: -18px;
  top: 44%;
  transform: rotate(-24deg);
  background: rgba(170, 18, 18, 0.9);
  color: #fff;
  font-size: 1.05rem;
  font-weight: 900;
  text-align: center;
  letter-spacing: 0.08em;
  padding: 6px 0;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
  pointer-events: none;
  z-index: 7;
}

/* Positioned as a % of card height so it always lands just below the name bar
   (the MTG title occupies ~the top 11% of a card) no matter how big the cards
   render — the stack overlaps below are sized to keep this strip visible. */
.deck-stack-badge {
  position: absolute;
  left: 5px;
  top: 12%;
  background: rgba(10, 8, 20, 0.88);
  color: var(--gold-soft);
  border: 1px solid rgba(217, 171, 74, 0.35);
  border-radius: 999px;
  padding: 1px 5px;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  font-weight: 600;
  pointer-events: none;
}

/* A hover-swap badge where either side of the swap is a land: the mana base
   is recomputed, not swapped card-for-card, so the app never applies these -
   dim + italic marks the delta as informational only, not an actionable one. */
.deck-stack-badge-inert {
  font-style: italic;
  white-space: nowrap;
  color: var(--muted);
  border-color: rgba(164, 155, 180, 0.4);
  box-shadow: none;
}

#deckbuilder-bench .deck-stack-card {
  margin-left: 0;
  width: 120px;
}

.basic-counter-card .deck-stack-badge {
  display: none;
}

.basic-counter-card .card-image,
.basic-counter-card img {
  filter: saturate(0.9) brightness(0.92);
}

/* Count and +/- live in one compact row inside the card's top strip, so every
   basic in the stack keeps its controls visible — not just the last one. */
.basic-counter-number {
  position: absolute;
  left: 0;
  right: 0;
  top: 16px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 1.25rem;
  font-weight: 600;
  color: #fff;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.9);
  pointer-events: none;
}

.basic-counter-controls {
  position: absolute;
  left: 8px;
  right: 8px;
  top: 15px;
  display: flex;
  justify-content: space-between;
  z-index: 3;
}

.basic-counter-controls button {
  border: 1px solid var(--line);
  background: rgba(19, 17, 32, 0.95);
  color: var(--ink);
  width: 26px;
  height: 26px;
  border-radius: 50%;
  padding: 0;
  font-size: 1rem;
  line-height: 1;
  font-weight: 700;
  touch-action: manipulation;
}

/* Touch devices need a ≥44px tap target on the basic-land +/- steppers. */
@media (pointer: coarse) {
  .basic-counter-controls button { width: 44px; height: 44px; font-size: 1.25rem; }
}

.cmc-board {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  overflow-x: auto;
  overflow-y: visible;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg-deep);
  padding: 20px 14px 12px 14px;
  min-height: 0;
}

.cmc-column {
  min-width: 128px;
  max-width: 128px;
  overflow: visible;
}

.cmc-label {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--muted);
  font-weight: 600;
  margin-bottom: 8px;
  text-align: center;
}

.cmc-stack {
  position: relative;
  min-height: 0;
  overflow: visible;
}

.cmc-stack .deck-stack-card {
  width: 120px;
  margin-left: 0;
  display: block;
}

/* -126px leaves a ~42px strip on the 168px-tall desktop cards, enough for the
   name bar plus the score badge (at 12% ≈ 20px) just below it to stay visible
   when cards stack. */
.cmc-stack .deck-stack-card + .deck-stack-card {
  margin-top: -126px;
}

/* Show basic-land counters with lighter overlap so count and +/- stay readable. */
.cmc-stack .basic-counter-card + .basic-counter-card {
  margin-top: -86px;
}

/* ---- Hover zooms ------------------------------------------------------------ */

#deck-hover-zoom {
  position: fixed;
  width: 280px;
  aspect-ratio: 5 / 7;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--gold-deep);
  box-shadow: 0 16px 36px rgba(0, 0, 0, 0.6);
  background: transparent;
  pointer-events: none;
  z-index: 10000;
  display: none;
}

#deck-hover-zoom.visible {
  display: block;
}

#deck-hover-zoom img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* Deckbuilder: pin the score breakdown to a fixed bottom-right corner
   instead of following the hovered card, so hovering pool cards only swaps
   its content and never repositions it or nudges page scroll (MTGA-overlay
   style). Draft-pack and pick-list hovers are unaffected (see
   positionScorecard in app.js). The enlarged card zoom keeps its original
   placement beside the hovered card. */
.scorecard.scorecard--pinned {
  position: fixed;
  right: 16px;
  bottom: 16px;
  left: auto;
  top: auto;
  max-height: calc(100vh - 32px);
  overflow-y: auto;
}

#pick-list-hover-zoom {
  position: fixed;
  width: 260px;
  aspect-ratio: 5 / 7;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--gold-deep);
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.55);
  background: transparent;
  pointer-events: none;
  z-index: 10000;
  display: none;
}

#pick-list-hover-zoom.visible {
  display: block;
}

#pick-list-hover-zoom img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* Tap-to-zoom lightbox for the mobile pack sheet (see sc-zoom-btn /
   openCardLightbox in app.js). Full-screen dimmed backdrop with the card at
   full viewport width, legible on a phone (Scryfall normal size holds up at
   375px). Also covers the phone-landscape dock (max-height: 500px below). */
.card-lightbox {
  position: fixed;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(8, 8, 12, 0.88);
  z-index: 10500;
}
.card-lightbox.visible { display: flex; }
.card-lightbox-img {
  width: 100%;
  max-width: 480px;
  max-height: 100vh;
  object-fit: contain;
  display: block;
  border-radius: 14px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.7);
}
.card-lightbox-close {
  position: absolute;
  top: max(14px, env(safe-area-inset-top, 0px));
  right: 14px;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
}
.card-lightbox-close:hover,
.card-lightbox-close:focus-visible { border-color: var(--gold); color: var(--gold); }

/* Phone landscape dock (isLandscapeMobileDock): the short viewport still gets
   the full-screen lightbox, sized to fit the reduced height. */
@media (max-height: 500px) and (pointer: coarse) { /* MQ.PHONE_LANDSCAPE */
  .card-lightbox-img { max-height: 100vh; }
}

/* Background scroll lock while the lightbox is open (set on <body> in
   openCardLightbox/closeCardLightbox). */
body.lightbox-open { overflow: hidden; }

.drop-active {
  outline: 2px dashed var(--gold);
  outline-offset: 2px;
}

body.deckbuilder-mode .layout {
  display: none;
}

body.deckbuilder-mode .deckbuilder-view {
  display: block;
}

/* ---- Modals ------------------------------------------------------------------ */

.info-modal {
  position: fixed;
  inset: 0;
  background: rgba(8, 6, 16, 0.72);
  z-index: 50000;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 40px 16px 40px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.info-modal[hidden] { display: none; }

.info-modal-box {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 28px 32px;
  max-width: 680px;
  width: 100%;
  position: relative;
}

.info-modal-box h2 {
  margin: 0 0 16px;
  font-family: var(--font-display);
  font-size: 1.35rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--ink);
}

.info-modal-box h3 {
  margin: 20px 0 8px;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--gold);
  text-transform: uppercase;
  letter-spacing: 0.12em;
}

.info-modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 32px;
  height: 32px;
  padding: 0;
  border-radius: 50%;
  font-size: 1rem;
  line-height: 1;
  font-weight: 700;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--ink);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.info-modal-close:hover { border-color: var(--gold); }

/* ---- Feedback modal ------------------------------------------------------------ */

.feedback-modal-box { max-width: 480px; }

.feedback-form { display: flex; flex-direction: column; gap: 10px; margin-top: 4px; }

.feedback-label {
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--muted);
  margin-bottom: -6px;
}

.feedback-input,
.feedback-textarea {
  width: 100%;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 10px;
  font-family: inherit;
  font-size: 0.9rem;
  color: var(--ink);
  background: var(--bg-deep);
  resize: vertical;
}

.feedback-input::placeholder,
.feedback-textarea::placeholder {
  color: #9088a6;
}

.feedback-input:focus-visible,
.feedback-textarea:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
  border-color: var(--gold);
}

.feedback-checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.88rem;
  cursor: pointer;
}

.feedback-error {
  font-size: 0.85rem;
  color: #f1a49b;
  padding: 6px 10px;
  background: rgba(224, 104, 90, 0.12);
  border: 1px solid rgba(224, 104, 90, 0.4);
  border-radius: 6px;
}

.feedback-actions { display: flex; justify-content: flex-end; margin-top: 4px; }

#feedback-send-btn {
  padding: 9px 20px;
}

/* ---- Controls / methodology tables ------------------------------------------- */

.controls-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}

.controls-table td {
  padding: 6px 10px 6px 0;
  vertical-align: top;
  border-bottom: 1px solid var(--line-soft);
  color: var(--muted);
}

.controls-table td:first-child {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  padding-right: 20px;
  min-width: 220px;
}

.controls-table tr:last-child td { border-bottom: none; }

/* Pointer-specific controls rows (see the Deckbuilder table in index.html):
   drag-and-drop and modifier chords don't exist on a touchscreen, and the
   tap equivalents are noise on a mouse, so each device is shown only the
   half that works for it. Untagged rows apply to both. */
.controls-table tr[data-pointer="coarse"] { display: none; }
@media (hover: none), (pointer: coarse) { /* MQ.COARSE_POINTER */
  .controls-table tr[data-pointer="fine"] { display: none; }
  .controls-table tr[data-pointer="coarse"] { display: table-row; }

  /* Touch move control for every layout that still shows real mini-cards:
     landscape phones and touch tablets. HTML5 drag-and-drop never fires from
     touch, so without this the deck can only be edited by the bench two-tap
     swap, which always trades card-for-card and so can never take the deck from
     23 spells to 22. A corner overlay rather than the portrait row-end strip,
     since there is no row to sit at the end of. The portrait block later in the
     file re-styles this back into the strip (same selector, later source order). */
  .deck-stack-move-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    right: 3px;
    bottom: 3px;
    z-index: 3;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 50%;
    background: rgba(12, 12, 14, 0.82);
    color: var(--gold-soft);
    font-size: 1.05rem;
    line-height: 1;
  }

  .deck-stack-move-btn:active { background: var(--line); }

  /* The stacked-card overlap hides all but the top ~54px of every card except
     the last, which is exactly where a bottom-anchored button would land. Only
     the fully-visible top edge is reliably tappable, so ride there instead. */
  .cmc-stack .deck-stack-card:not(:last-child) .deck-stack-move-btn {
    top: 3px;
    bottom: auto;
  }
}

.method-intro {
  font-size: 0.88rem;
  color: var(--muted);
  margin: 0 0 10px;
}

.method-list {
  margin: 0;
  font-size: 0.88rem;
}

.method-list dt {
  font-weight: 700;
  margin-top: 10px;
}

.method-list dd {
  margin: 2px 0 0 0;
  color: var(--muted);
  line-height: 1.45;
}

/* ---- Set selector (the opening moment) ---------------------------------------- */

.set-select-overlay {
  position: fixed;
  inset: 0;
  background:
    radial-gradient(900px 480px at 50% -180px, rgba(42, 36, 80, 0.9) 0%, rgba(14, 12, 26, 0.94) 70%),
    var(--bg-deep);
  z-index: 60000;
  display: flex;
  align-items: center;
  justify-content: center;
}

.set-select-overlay[hidden] { display: none; }

.set-select-box {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  /* Extra top room so the corner close button clears the centred heading. */
  padding: 48px 40px 32px;
  max-width: 540px;
  width: 100%;
  text-align: center;
}

.set-select-box h2 {
  margin: 0 0 20px;
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--ink);
}

.set-select-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.set-select-list button {
  width: 100%;
  padding: 14px 20px;
  font-size: 1rem;
  border-radius: 10px;
}

/* Set-choice rows: a user-supplied symbol in front of the set name. Neutral
   panel (not the loud gold of the primary buttons) so the symbol art reads. */
.set-select-box { position: relative; }

.set-select-sub {
  margin: -8px 0 20px;
  color: var(--muted);
  font-size: 0.9rem;
}

.set-select-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 30px;
  height: 30px;
  padding: 0;
  display: grid;
  place-items: center;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--muted);
  cursor: pointer;
}
.set-select-close svg { display: block; }
.set-select-close:hover { color: var(--ink); border-color: var(--gold-deep); }

.set-select-list .set-choice {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 14px 18px;
  text-align: left;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  color: var(--ink);
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease, transform 120ms ease;
}
.set-select-list .set-choice:hover {
  background: var(--panel);
  border-color: var(--gold);
  transform: translateY(-1px);
}

/* Fixed-size slot (contain) so symbols of different aspect ratios (a square
   eclipse vs a wide owl) sit in an identical box — same visual size AND aligned
   left edges, so the set names line up in a column. */
.set-choice-symbol {
  width: 52px;
  height: 30px;
  flex: none;
  object-fit: contain;
}
.set-choice-symbol.is-missing { display: none; }

.set-choice-name {
  /* min-width: 0 overrides the flex-item default (content's intrinsic width),
     which otherwise refuses to shrink below the unbroken name — the cause of
     long names (e.g. a five-word set name) pushing the row off-screen.
     white-space: normal undoes the base `button { white-space: nowrap }`
     rule, inherited from the .set-choice button this span lives in, which
     otherwise blocks wrapping outright. */
  flex: 1 1 auto;
  min-width: 0;
  white-space: normal;
  overflow-wrap: break-word;
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}

/* Data-confidence badge on each set row: how much real data backs its ratings. */
.set-choice-tier {
  flex: none;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.set-choice-tier.dt-full { color: var(--mana-g); border-color: rgba(47, 158, 79, 0.4); background: rgba(47, 158, 79, 0.12); }
.set-choice-tier.dt-draft { color: var(--gold-soft); border-color: rgba(217, 171, 74, 0.4); background: rgba(217, 171, 74, 0.12); }
.set-choice-tier.dt-cold { color: var(--muted); border-color: var(--line); background: var(--panel); }

.set-select-dropdown {
  background: var(--panel-2);
  border: 1px solid var(--line);
  color: var(--ink);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 0.86rem;
  cursor: pointer;
  font-family: inherit;
  font-weight: 600;
  height: 36px;
  /* A native <select> otherwise sizes itself to the longest option (e.g. a
     five-word set name), which pushes the topbar's button row off-screen on
     mobile. Cap the closed control's width and truncate — the open dropdown
     list itself is unaffected and still shows the full name. */
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.set-select-dropdown:hover { border-color: var(--gold); }

/* ---- Responsive ---------------------------------------------------------------- */

/* Deckbuilder bench: the fixed 10x120px grid needs 1288px, which clears a
   1440px+ desktop but overflows a 1280px laptop viewport (before the 640px
   mobile breakpoint below reflows it) — let columns share the available
   width instead of forcing horizontal page scroll. */
@media (max-width: 1439px) {
  #deckbuilder-bench.stack-row {
    grid-template-columns: repeat(10, minmax(0, 1fr));
  }

  #deckbuilder-bench .deck-stack-card {
    width: 100%;
  }
}

/* The lane panel shrinks (clipping its readout) to stay on the top row down to
   tablet widths; only below this does it drop to its own full-width row, where
   there is no longer horizontal room for the meter alongside the action group.
   Removing the Export State button freed enough width to keep the lane up on
   laptops (1366/1440). */
@media (max-width: 1024px) {
  .topbar { flex-wrap: wrap; gap: 8px; }
  .lane-panel {
    order: 3;
    width: 100%;
    margin: 0;
    min-width: 0;
  }
}

@media (max-width: 980px) {
  /* minmax(0, 1fr), not bare 1fr: 1fr's auto minimum lets the pack grid's
     min-content pin the column at its desktop width on a live resize down
     (Chromium keeps the stale measurement), forcing horizontal overflow.
     A 0 minimum makes the column track the viewport, like the desktop rule. */
  .layout { grid-template-columns: minmax(0, 1fr); }
  .side-panel { order: -1; }
}

/* Final Deck panel: the 4-across strip only has room on wide screens —
   stack each section full-width below this and swap side borders for
   bottom dividers. */
@media (max-width: 860px) {
  .fdp-head,
  .fdp-curve,
  .fdp-mana,
  .fdp-stats {
    flex: 1 1 100%;
    border-right: none;
    padding-right: 0;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--line-soft);
  }

  .fdp-stats { border-bottom: none; padding-bottom: 0; }
}

@media (max-width: 640px) {
  h1 { font-size: 1.05rem; }

  .topbar { padding: 10px 12px; }

  /* The mono power line is wider than a phone; let it wrap instead of
     forcing the whole page into horizontal scroll. */
  .lane-power { white-space: normal; }

  /* Buttons wrap onto extra rows so every action stays reachable without
     horizontal scrolling (a scrolling row hid Auto Draft/Export off-screen). */
  .top-actions {
    width: 100%;
    flex-wrap: wrap;
    row-gap: 6px;
  }

  button {
    padding: 6px 10px;
    font-size: 0.82rem;
    white-space: nowrap;
  }

  /* 2 columns on small phones, fills naturally on larger ones */
  .pack-grid {
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 8px;
  }

  /* Deckbuilder bench: responsive grid instead of fixed 10-column 1200px layout */
  #deckbuilder-bench.stack-row {
    grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
    grid-auto-rows: 124px;
    min-height: 260px;
    max-height: 260px;
  }

  #deckbuilder-bench .deck-stack-card {
    width: 100%;
  }

  /* CMC board: narrower columns so more fit without overflow */
  .cmc-column {
    min-width: 90px;
    max-width: 90px;
  }

  .cmc-stack .deck-stack-card {
    width: 88px;
  }

  /* -86px leaves a ~37px strip on the 123px-tall mobile cards, so the name bar
     plus the score badge just under it both stay visible when cards stack. */
  .cmc-stack .deck-stack-card + .deck-stack-card {
    margin-top: -86px;
  }

  /* Keep basic-land counters loose enough that every count and +/- row stays
     visible (must come after the generic overlap rule — equal specificity). */
  .cmc-stack .basic-counter-card + .basic-counter-card {
    margin-top: -72px;
  }

  .deckbuilder-toolbar { flex-wrap: wrap; }

  .final-deck-panel { padding: 12px; gap: 12px; }
  .fdp-count { font-size: 1.4rem; }
}

/* ---- Mobile pass: header, filters, deck/bench list rows -------------------------
   Targets phone-SHAPED viewports, not merely narrow ones, and the same band the
   topbar/lane-panel/filter JS in app.js uses (PHONE_LAYOUT_MQ — keep the two
   strings identical). A phone in landscape is ~852x393: too wide for the 700px
   half of this query, but with less height than portrait, so it needs the
   collapsed header, the collapsible Final Deck summary and the list rows more
   than portrait does, not less. Gating on width alone left rotation on the full
   desktop layout, where the topbar ate ~300px of a 393px viewport and the
   10-column 168px bench grid opened a dead band between its two rows.
   The second half is pointer-gated so a short desktop window is unaffected.
   Placed after the 640px block above so its list-row layout for .deck-stack-card
   wins over that block's smaller-but-still-mini-card sizing at the same width. */
@media (max-width: 700px), (max-height: 500px) and (pointer: coarse) { /* MQ.PHONE_LAYOUT */
  /* ---- Sticky header: shrink the steady state, then let JS collapse the
     lane panel + action rows further on scroll-down (topbar--compact). The
     brand row alone is ~46px, versus ~390px for all four rows at rest. ---- */
  .topbar { padding: 8px 12px; row-gap: 6px; }
  .brand-logo { width: 24px; height: 24px; }
  .brand-kicker { font-size: 0.5rem; letter-spacing: 0.28em; }
  .brand-name { font-size: 1.05rem; }
  .info-actions { margin-left: auto; gap: 6px; }

  .lane-panel { padding: 4px 10px; gap: 8px; }
  .lane-meter { height: 22px; gap: 3px; }
  .lane-band { width: 11px; }
  .lane-band b { font-size: 0.5rem; }
  .lane-colors { margin-bottom: 0; font-size: 0.76rem; }
  /* Single-line lane panel: the per-color power readout is the detail that
     doesn't fit next to the meter + "Lane: W/R" label at this width — it's
     still one tap away via the Controls modal / final-deck panel. */
  .lane-power { display: none; }

  .info-actions,
  .top-actions,
  .lane-panel {
    transition: max-height 180ms ease, opacity 140ms ease, margin 180ms ease, padding 180ms ease;
    max-height: 120px;
    overflow: hidden;
  }

  .topbar--compact .info-actions,
  .topbar--compact .top-actions,
  .topbar--compact .lane-panel {
    max-height: 0;
    opacity: 0;
    margin: 0;
    padding-top: 0;
    padding-bottom: 0;
    border-width: 0;
    pointer-events: none;
  }

  /* ---- Filter panel: collapsed by default behind a "Filters" toggle, so the
     bench/deck below aren't pushed ~1500px down the page. ---- */
  .filter-toggle-btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    height: 44px;
    padding: 0 14px;
    margin-bottom: 8px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 10px;
    color: var(--ink);
    font-family: inherit;
    font-weight: 600;
    font-size: 0.86rem;
  }
  .filter-toggle-chevron { transition: transform 140ms ease; }
  .filter-toggle-btn.is-open .filter-toggle-chevron { transform: rotate(180deg); }

  /* ---- Final Deck summary: collapsed to its head by default (see the
     #fdp-toggle handler in app.js). Expanded it is ~390px tall, which at 812px
     of viewport put every card of the deck below the fold on arrival. The head
     keeps the numbers you actually steer by (count, spells/lands, colors); the
     curve, stat grid and castability line are one tap away. ---- */
  .fdp-toggle-chevron { display: block; }
  .final-deck-panel.fdp-collapsed .fdp-toggle-chevron { transform: rotate(-90deg); }
  .final-deck-panel.fdp-collapsed .fdp-detail { display: none; }
  .final-deck-panel.fdp-collapsed { gap: 0; }
  .final-deck-panel.fdp-collapsed .fdp-head { padding-bottom: 0; border-bottom: none; }
  .fdp-head { min-height: 44px; align-items: center; }
  .fdp-head-text { flex: 1 1 auto; }

  .deckbuilder-filter-bar { display: none; }
  .deckbuilder-filter-bar.filters-open {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }
  /* The row layout's `flex: 1 1 200px` is a width up there, but this block
     stacks the bar into a column, where the same basis becomes a 200px-tall
     search group with ~140px of dead space under the input. Size to content. */
  .deckbuilder-filter-bar.filters-open .filter-search {
    flex: 0 0 auto;
    min-width: 0;
  }

}

/* ---- Portrait phones ONLY (the block above stays width-or-short-landscape).
   The list rows below trade card art for a text label: the right trade at 390px
   of width, the wrong one in landscape, where 844px fits the real cards and
   reading them is the whole point. Landscape phones therefore keep the desktop
   mini-card layout, and pick the touch move control back up from the
   MQ.COARSE_POINTER block instead of the row-end strip defined here. ---- */
@media (max-width: 700px) and (orientation: portrait) { /* MQ.PHONE_PORTRAIT */
  /* ---- Deck stacks + bench: swap the mini-card presentation (name and score
     illegible at ~88x123px, badge covering the art) for compact list rows.
     The .deck-stack-mobile-info name/mana text (added in app.js for every
     card, desktop just never shows it) becomes the row's label; tapping a
     row still opens the same scorecard / hover-zoom flow as before — only the
     at-rest layout changes here, not the interaction wiring. ---- */
  .cmc-board {
    flex-direction: column;
    align-items: stretch;
    overflow-x: visible;
    padding: 10px;
  }

  .cmc-column { min-width: 100%; max-width: 100%; }

  .cmc-label { text-align: left; margin: 12px 0 6px; }
  .cmc-column:first-child .cmc-label { margin-top: 0; }

  .cmc-stack {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  /* The bench used to be a 320px window scrolling ~875px of cards. Nested
     inside a page that also scrolls, a touch drag starting on the bench moved
     the bench and a drag starting 10px away moved the page, which is the worst
     kind of "why did nothing happen". One scroll surface only: the bench grows
     to its content and the page does all the scrolling. */
  #deckbuilder-bench.stack-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-height: 0;
    max-height: none;
    overflow: visible;
    padding: 8px;
  }

  .deck-stack-card,
  .cmc-stack .deck-stack-card,
  #deckbuilder-bench .deck-stack-card {
    position: relative;
    width: 100%;
    aspect-ratio: auto;
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 48px;
    margin: 0 !important;
    padding: 5px 8px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--panel-2);
  }

  .cmc-stack .deck-stack-card:hover,
  .cmc-stack .deck-stack-card:focus,
  .deck-stack-card:hover,
  .deck-stack-card:focus,
  .deck-stack-card.deck-stack-card--hover-held {
    transform: none !important;
    box-shadow: none !important;
    border-color: var(--gold-deep);
  }

  .deck-stack-card img {
    width: 34px;
    height: 46px;
    flex: none;
    object-fit: cover;
    object-position: top center;
    border-radius: 4px;
  }

  .deck-stack-mobile-info {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1 1 auto;
    gap: 1px;
  }

  .deck-stack-name-mobile {
    font-size: 0.84rem;
    font-weight: 600;
    color: var(--ink);
    text-align: left;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .deck-stack-mana-mobile {
    font-family: var(--font-mono);
    font-size: 0.68rem;
    color: var(--muted);
    text-align: left;
  }

  .deck-stack-badge {
    position: static;
    flex: none;
    margin-left: auto;
    white-space: nowrap;
  }

  /* "Δ+0.00" on every row is ~60px of nothing (it only means something with a
     swap armed or hovered) and it was truncating card names. Desktop has the
     width to keep it always. */
  .deck-stack-badge--zero-delta .deck-stack-badge-delta { display: none; }

  /* ---- One-tap move: the only way to move a single card on a touchscreen.
     HTML5 drag-and-drop never fires from touch and there are no modifier keys,
     so before this the deck could only be edited by the bench two-tap swap —
     which always trades a card for a card, and so could never take the deck
     from 23 spells to 22, or drop a card without promoting another. "+" pulls a
     bench card in, "−" sends a deck card back, both through the same
     moveCardBetweenDeckZones the desktop drop handler uses. 44px so it clears
     the minimum touch target, and it sits after the score badge so a
     mis-aimed tap lands on the row (opens the scorecard) rather than moving a
     card by accident. ---- */
  .deck-stack-move-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    /* Undo the MQ.COARSE_POINTER card-corner overlay: a touch phone in portrait
       matches BOTH blocks, and an absolutely-positioned button would drop out of
       the row's flex flow and land on top of the card name. */
    position: static;
    width: 44px;
    height: 44px;
    margin: -5px -8px -5px 4px;
    padding: 0;
    background: none;
    border: none;
    border-left: 1px solid var(--line);
    border-radius: 0 8px 8px 0;
    color: var(--gold-soft);
    font-size: 1.3rem;
    line-height: 1;
  }

  .deck-stack-move-btn:active { background: var(--line); }

  .deck-stack-ignored-label {
    position: static;
    transform: none;
    flex: none;
    font-size: 0.7rem;
    padding: 2px 8px;
    margin-left: auto;
  }

  /* Basic-land rows: same row shell, but the count/name/steppers replace the
     name+mana+badge trio (basics have neither). */
  .basic-counter-card {
    padding: 5px 8px;
  }

  .deck-stack-name-mobile--basic {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.84rem;
    font-weight: 600;
    color: var(--ink);
  }

  .basic-counter-card img { width: 34px; height: 46px; }

  .basic-counter-number {
    position: static;
    height: auto;
    font-size: 1.05rem;
    flex: none;
  }

  .basic-counter-controls {
    position: static;
    flex: none;
    width: auto;
    gap: 8px;
  }

  .basic-counter-controls button { width: 44px; height: 44px; }
}

@media (max-width: 700px), (max-height: 500px) and (pointer: coarse) {

  /* ---- Set picker: the fixed 40px side padding left a ~145px column for the
     name at 375px width, narrow enough that "Strixhaven" broke mid-word.
     Tighter padding + letting the tier badge drop to its own line (instead of
     competing with the name for the same row) frees enough width that names
     wrap on spaces, never inside a word. ---- */
  .set-select-overlay { padding: 16px; }
  .set-select-box { padding: 36px 16px 20px; max-width: 100%; }
  .set-select-box h2 { font-size: 1.25rem; }
  .set-select-list .set-choice { flex-wrap: wrap; gap: 6px 12px; padding: 12px; }
  /* The base rule's overflow-wrap:break-word let a name column this narrow
     break a long single word mid-letter ("Strixhaven" -> "Strixha-ven"); drop
     back to only wrapping at spaces, and give the tier badge its own row
     (flex-basis:100% forces the wrap point) so the name isn't fighting it for
     width on the same line in the first place. */
  .set-choice-name {
    font-size: 1rem;
    overflow-wrap: normal;
    word-break: normal;
  }
  .set-choice-tier { flex-basis: 100%; }
}

/* ---- Auto Build / Regenerate loading overlay -------------------------------------
   Centered while the backend deck build is in flight. Signature: the "shuffle"
   glyph reuses this app's own stacked-card motif (see .deck-stack-card) instead
   of a generic ring spinner, three card silhouettes lighting up gold in
   sequence like a riffle shuffle, so the wait reads as "your deck is being
   assembled," not just "something is loading." */

.db-loading-overlay {
  position: fixed;
  inset: 0;
  /* Above the sticky topbar (z-index 30000) so the build overlay fully covers
     and blocks the page, topbar buttons included, while the deck is building. */
  z-index: 40000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(14, 12, 26, 0.72);
  backdrop-filter: blur(2px);
}
.db-loading-overlay[hidden] { display: none; }

.db-loading-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 28px 40px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: 0 20px 46px rgba(0, 0, 0, 0.55);
}

.db-shuffle {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 34px;
}

.db-shuffle-card {
  width: 18px;
  height: 26px;
  border-radius: 4px;
  background: var(--panel-2);
  border: 1px solid var(--line);
  margin: 0 -4px;
  animation: db-shuffle-pulse 1.2s ease-in-out infinite;
}
.db-shuffle-card:nth-child(1) { transform: rotate(-10deg); animation-delay: 0s; }
.db-shuffle-card:nth-child(2) { transform: rotate(0deg); animation-delay: 0.2s; z-index: 1; }
.db-shuffle-card:nth-child(3) { transform: rotate(10deg); animation-delay: 0.4s; }

@keyframes db-shuffle-pulse {
  0%, 100% { border-color: var(--line); box-shadow: none; }
  40% { border-color: var(--gold); box-shadow: 0 0 12px rgba(217, 171, 74, 0.55); }
}

.db-loading-title {
  margin: 0;
  font-size: 0.86rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--ink);
}

.db-loading-sub {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---- Mobile draft pass 2: art-crop pack grid, landscape scorecard dock -----------
   Phone-only (gated the same way as the rest of the mobile pass — the JS side
   reads isMobileScorecard()/isCoarsePointer(); these are the CSS-only pieces:
   grid density and the compact tile). Desktop stays exactly as it was above. */
@media (max-width: 700px) and (orientation: portrait) { /* MQ.PHONE_PORTRAIT */
  /* Denser grid: 3 tiles per row so the full pack fits in ~1.5 screens
     instead of the 2-column full-card layout. */
  .pack-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
  }

  /* Art-crop tile: a shorter box than the full 5/7 card, cropped toward the
     art band (object-position keeps the top ~12% — past the title bar —
     centered in frame) rather than the whole illustrated card. No server/data
     change: this crops the same full card image the desktop grid already
     has via image_url. */
  .card-image {
    aspect-ratio: 5/4;
    object-position: center 12%;
  }

  .rating-badge {
    top: 5px;
    left: auto;
    right: 5px;
    font-size: 0.68rem;
    padding: 2px 6px;
  }

  .pack-card-mobile-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 4px 6px 6px;
  }

  .pack-card-name-mobile {
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--ink);
    line-height: 1.15;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .pack-card-mana-mobile {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
  }
  .pack-card-mana-mobile .pip { width: 11px; height: 11px; }
  .pack-card-mana-mobile .pip-generic { font-size: 0.6rem; }
}

/* ---- Phone landscape: docked side panel + denser grid ----------------------------
   Rotated phone (short viewport) — matches isLandscapeMobileDock() in app.js.
   The scorecard keeps its ".sheet" class and JS-owned show/hide; only its
   placement changes here, from a bottom sheet to a right-side panel, so it no
   longer covers most of the (now wider-than-tall) pack grid. */
@media (max-height: 500px) and (pointer: coarse) { /* MQ.PHONE_LANDSCAPE */
  .pack-grid {
    grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
    gap: 6px;
  }

  .rating-badge {
    top: 4px;
    left: auto;
    right: 4px;
    font-size: 0.66rem;
    padding: 2px 5px;
  }

  .pack-card-mobile-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 3px 5px 5px;
  }
  .pack-card-name-mobile {
    font-size: 0.66rem;
    font-weight: 600;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .pack-card-mana-mobile { display: flex; flex-wrap: wrap; gap: 2px; }
  .pack-card-mana-mobile .pip { width: 10px; height: 10px; }

  .scorecard.sheet {
    left: auto;
    right: 0;
    top: 0;
    bottom: 0;
    width: 42%;
    min-width: 260px;
    max-width: 400px;
    max-height: 100vh;
    border-radius: 18px 0 0 18px;
    border-right: none;
    padding: 14px 14px calc(14px + env(safe-area-inset-bottom, 0px));
  }

  .scorecard.sheet::before {
    /* The tray-lip handle reads as "slide up"; the side dock slides in from
       the right instead, so the handle affordance doesn't apply here. */
    display: none;
  }

  .scorecard.sheet.visible {
    animation: sc-sheet-in-side 200ms cubic-bezier(0.22, 1, 0.36, 1) both;
  }
}

@keyframes sc-sheet-in-side {
  from { opacity: 0; transform: translateX(100%); }
  to { opacity: 1; transform: translateX(0); }
}

/* ---- Reduced motion -------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
  .card:hover { transform: none; }
}
