.packsim {
  width: min(1180px, calc(100% - 32px));
  margin: 0 auto 72px;
  padding-top: 16px;
  display: grid;
  gap: 16px;
}

.packsim-head {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 18px;
  align-items: center;
}

.packsim-head h1 {
  font-size: 22px;
  letter-spacing: -0.03em;
  margin: 0;
}

.packsim-status {
  color: var(--muted);
  margin: 0 0 0 auto;
  font-size: 13px;
}

/* Two columns, always: the control rail, then whatever the second column is *for* right now.
   Before the tear that is the sealed pack; after it, the opened cards — the stage leaves the grid
   entirely (see `.pack-stage[data-mode="overview"]`). A third track held open for a torn-open
   stage is a labeled empty box, which is exactly what the user rejected. */
.packsim-workspace {
  display: grid;
  grid-template-columns: minmax(220px, 280px) minmax(280px, 1fr);
  gap: 16px;
  align-items: start;
}

/* Overview: column 2 is now the results rail, so give it the wider floor the card grid wants. */
.packsim-workspace:has(#packStage[data-mode="overview"]) {
  grid-template-columns: minmax(220px, 280px) minmax(320px, 1fr);
}

/* Nothing has been opened yet, so this node holds nothing. A `display: grid` empty box would be
   auto-placed as a third row under the controls and push the pack down; it joins the layout only
   once there is something in it. */
.packsim-results {
  display: none;
  gap: 14px;
  align-content: start;
  min-width: 0;
  min-height: 0;
}

.packsim-workspace:has(#packStage[data-mode="overview"]) .packsim-results {
  display: grid;
}

.packsim-source {
  color: var(--faint);
  font-size: 13px;
  line-height: 1.7;
  max-width: 86ch;
}

.packsim-source summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-weight: 700;
}

.packsim-source p {
  margin: 10px 0 0;
}

.packsim-source a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.packsim-source a:hover,
.packsim-source a:focus-visible {
  color: var(--ink);
}

.packsim-controls {
  display: grid;
  gap: 10px;
  padding: 14px;
  background: var(--panel);
  border: 1px solid var(--line);
}

.packsim-controls label {
  display: grid;
  gap: 6px;
  font-size: 12px;
  color: var(--faint);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.packsim-controls select,
.packsim-controls input {
  min-width: 140px;
  min-height: 38px;
  padding: 0 10px;
}

.packsim-controls #packOpen {
  background: var(--accent);
  color: #1a1204;
  border-color: transparent;
}

.packsim-controls .is-disabled {
  opacity: 0.45;
}

.packsim-advanced {
  align-self: end;
  font-size: 12px;
  color: var(--faint);
}

.packsim-advanced summary {
  cursor: pointer;
  min-height: 38px;
  display: flex;
  align-items: center;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.packsim-advanced label {
  margin-top: 8px;
}

.packsim-tabs {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--line);
}

.packsim-tabs button {
  min-height: 36px;
  padding: 0 12px;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--faint);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: 12px;
}

.packsim-tabs button[aria-selected="true"] {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

.packsim-body[data-tab="open"] #packEvPane,
.packsim-body[data-tab="ev"] #packOpenPane {
  display: none;
}

.packsim-open-pane,
.packsim-ev {
  display: grid;
  gap: 22px;
}

.packsim-ev {
  padding: 18px;
  background: var(--panel);
  border: 1px solid var(--line);
}

.packsim-ev h2 {
  font-size: 22px;
  letter-spacing: -0.03em;
}

.packsim-ev header p {
  color: var(--muted);
  margin-top: 8px;
  max-width: 52ch;
}

.pack-ev-board {
  display: grid;
  gap: 18px;
}

.pack-ev-set h3 {
  margin: 0 0 8px;
  font-size: 15px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
}

.pack-ev-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.pack-ev-table th,
.pack-ev-table td {
  padding: 8px 10px;
  text-align: right;
  border-bottom: 1px solid var(--line);
}

.pack-ev-table th:first-child,
.pack-ev-table td:first-child {
  text-align: left;
}

.pack-ev-table thead th {
  color: var(--faint);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
}

.pack-ev-table .is-up {
  color: var(--ok);
}

.pack-ev-table .is-down {
  color: var(--danger);
}

.pack-ev-rates {
  margin: 8px 0 0;
  color: var(--muted);
  font-size: 13px;
}

.pack-summary {
  margin: 0 0 12px;
  padding: 12px 14px;
  background: var(--ink);
  color: var(--bg);
  font-size: 15px;
  font-weight: 800;
  letter-spacing: -0.01em;
}

.pack-card-popover {
  position: fixed;
  z-index: 40;
  width: min(760px, calc(100vw - 16px));
  max-height: min(70vh, 640px);
  overflow: auto;
  border: 1px solid var(--line);
  background: var(--panel);
  box-shadow: 0 24px 80px rgb(0 0 0 / 55%);
}

.pack-card-popover .detail {
  grid-template-columns: minmax(180px, 240px) 1fr;
  gap: 16px;
  padding: 16px;
}

.pack-card-popover .detail-copy {
  padding-right: 0;
}

.pack-card-popover .detail-copy h2 {
  font-size: 22px;
}

@media (hover: none), (pointer: coarse) {
  .pack-card-popover {
    display: none !important;
  }
}

.packsim-tally {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 18px;
  color: var(--muted);
  font-size: 14px;
}

.packsim-tally strong {
  color: var(--ink);
  font-size: 28px;
  letter-spacing: -0.03em;
}

.pack-stage {
  min-height: min(72vh, 640px);
  display: grid;
  place-items: center;
  gap: 16px;
  padding: 20px 12px 28px;
  background: var(--bg-2);
  border: 1px solid var(--line);
  overflow: hidden;
  perspective: 900px;
}

.pack-wrapper {
  position: relative;
  width: min(300px, 78vw);
  aspect-ratio: 63 / 88;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  color: var(--ink);
  display: grid;
  padding: 0;
  cursor: grab;
  transform-origin: 50% 0%;
  transform-style: preserve-3d;
  --peel: 0;
  touch-action: none;
}

/* Origins is two entries in the picker (OGN / OGN-KR) but one printed booster, and OGN-KR is the
   default pick — without its own selector the wrapper the user first sees has no set skin. */
.pack-stage[data-set="OGN"] .pack-wrapper,
.pack-stage[data-set="OGN-KR"] .pack-wrapper {
  background:
    linear-gradient(180deg, #1a2740 0%, #10182a 50%, #0b1018 100%);
}

.pack-stage[data-set="SFD"] .pack-wrapper {
  background:
    linear-gradient(180deg, #2a2418 0%, #16130e 55%, #0c0b09 100%);
}

.pack-stage[data-set="UNL"] .pack-wrapper {
  background:
    linear-gradient(180deg, #241428 0%, #140e18 55%, #0c090f 100%);
}

.pack-stage[data-set="VEN"] .pack-wrapper {
  background:
    linear-gradient(180deg, #2a1214 0%, #160c0e 55%, #0d0808 100%);
}

/* Every Nexus Night promo pack (OGN-NN … VEN-NN) wears the same night foil, because that is one
   product line across four sets — not four wrappers. */
.pack-stage[data-set$="-NN"] .pack-wrapper {
  background:
    linear-gradient(180deg, #131a3a 0%, #0d1026 52%, #07080f 100%);
}

.pack-wrapper-stack,
.pack-wrapper-body,
.pack-wrapper-flap {
  position: absolute;
  inset: 0;
  border-radius: 0;
}

/* The card stack sits behind the foil body. As the tear opens it rides up through the gap and
   gains opacity, so what the torn edge exposes is cards — not a hole in the stage. */
.pack-wrapper-stack {
  z-index: 0;
  background:
    linear-gradient(180deg, rgb(255 255 255 / 16%) 0 5%, transparent 5%),
    repeating-linear-gradient(90deg, #1a1018 0 18px, #24141e 18px 36px);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 8%);
  transform: translateY(calc(6px - var(--peel) * 15px)) scale(calc(0.96 + var(--peel) * 0.025));
  opacity: calc(0.34 + var(--peel) * 0.66);
}

.pack-wrapper-body {
  z-index: 2;
  overflow: hidden;
  background:
    linear-gradient(180deg, #1c2730 0%, #12181e 42%, #0d1318 100%);
  /* A straight horizontal inset reads as a wipe, not a tear. The top edge is a serrated line
     whose baseline drops with --peel, so the foil separates along a ragged cut the way a real
     wrapper does. */
  --tear: calc(var(--peel) * 34%);
  clip-path: polygon(
    0% var(--tear),
    6% calc(var(--tear) + 1.5%),
    12% calc(var(--tear) - 0.4%),
    19% calc(var(--tear) + 2.3%),
    25% calc(var(--tear) + 0.4%),
    31% calc(var(--tear) + 2.7%),
    38% calc(var(--tear) + 0.9%),
    44% calc(var(--tear) + 2.4%),
    50% calc(var(--tear) + 0.2%),
    57% calc(var(--tear) + 2.8%),
    63% calc(var(--tear) + 0.7%),
    69% calc(var(--tear) + 2.2%),
    76% calc(var(--tear) + 0.3%),
    82% calc(var(--tear) + 2.6%),
    88% calc(var(--tear) + 1%),
    94% calc(var(--tear) + 2%),
    100% var(--tear),
    100% 100%,
    0% 100%
  );
  box-shadow: var(--shadow);
}

.pack-wrapper-flap {
  z-index: 3;
  transform-origin: 50% 0%;
  transform: rotateX(calc(var(--peel) * -165deg));
  transform-style: preserve-3d;
  pointer-events: none;
}

.pack-wrapper-flap-face {
  position: absolute;
  inset: 0 auto auto 0;
  width: 100%;
  height: 36%;
  overflow: hidden;
  backface-visibility: hidden;
}

.pack-wrapper-flap-front {
  background:
    linear-gradient(180deg, #243040 0%, #1c2730 100%);
  box-shadow: 0 8px 16px rgb(0 0 0 / 35%);
  clip-path: polygon(0 0, 100% 0, 100% 88%, 50% 100%, 0 88%);
}

.pack-wrapper-flap-back {
  transform: rotateX(180deg);
  background:
    linear-gradient(180deg, #c9b48a 0%, #8a7348 55%, #5c4a2c 100%);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 18%);
}

.pack-wrapper-flap-front .pack-wrapper-art {
  height: 280%;
  object-position: top;
}

.pack-wrapper-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.62;
  pointer-events: none;
}

.pack-wrapper-art[hidden] {
  display: none;
}

.pack-wrapper-copy {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 6px;
  justify-items: center;
  text-align: center;
  padding: 22px 18px 16px;
}

.pack-wrapper-brand {
  font-size: 11px;
  letter-spacing: 0.28em;
  color: var(--accent);
  font-weight: 800;
}

.pack-wrapper-copy strong {
  font-size: 22px;
  letter-spacing: 0.12em;
}

.pack-wrapper-hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 14px;
  font-size: 11px;
  color: var(--faint);
  z-index: 4;
  pointer-events: none;
}

/* "Enter" is a key name in both languages (.prd/24): a <kbd>, set in the hint's own type. */
.pack-wrapper-hint kbd {
  font: inherit;
}

/* Committing the tear pins --peel to 1, so the polygon, the flap rotation and the stack lift all
   land at their open pose even when the commit came from Enter or from a drag that stopped
   short. It is set on the parts, not the wrapper: the wrapper carries the drag's inline --peel,
   and an inline value on the parent always outranks a rule that targets the parent. */
.pack-wrapper.is-open .pack-wrapper-body,
.pack-wrapper.is-open .pack-wrapper-flap,
.pack-wrapper.is-open .pack-wrapper-stack {
  --peel: 1;
}

.pack-wrapper.is-open .pack-wrapper-flap {
  transform: rotateX(-175deg);
}

/* Only the committed tear animates. Putting a transition on the base selectors would make the
   drag lag a frame behind the pointer. */
.pack-wrapper.is-open .pack-wrapper-flap,
.pack-wrapper.is-open .pack-wrapper-body,
.pack-wrapper.is-open .pack-wrapper-stack {
  transition:
    transform 260ms cubic-bezier(0.2, 0.8, 0.2, 1),
    clip-path 260ms cubic-bezier(0.2, 0.8, 0.2, 1),
    opacity 220ms linear,
    filter 220ms linear;
}

/* Gold foil interior: the flash as the flap turns over is the moment the pack reads as opened. */
.pack-wrapper.is-peeling .pack-wrapper-flap-back,
.pack-wrapper.is-open .pack-wrapper-flap-back {
  filter: brightness(calc(1 + var(--peel) * 0.5));
}

.pack-wrapper.is-gone,
.pack-stage[data-mode="overview"] .pack-wrapper,
.pack-stage[data-mode="sequence"] .pack-wrapper {
  display: none;
}

.pack-stage[data-mode="idle"] .pack-wrapper,
.pack-stage[data-mode="wrapper"] .pack-wrapper {
  display: grid;
}

.pack-flip {
  min-height: 360px;
  display: grid;
  place-items: center;
  perspective: 900px;
}

/* The flip well only exists while a card is being turned over. In overview — and any time
   it holds nothing — it collapses, otherwise the opened pack reads as a 360px band of
   empty dark above the cards. */
.pack-stage[data-mode="overview"] .pack-flip,
.pack-flip:empty {
  display: none;
  min-height: 0;
}

/* By overview the wrapper is torn and the flip well is empty, so the stage holds nothing. Keeping
   it as a shrunken box labeled "뜯음" reserved ~320px of dead width between the controls and the
   cards. It leaves the grid instead; the workspace drops to controls | results above, which is
   what keeps the contents to the right of the opening rather than under it. */
.pack-stage[data-mode="overview"] {
  display: none;
}

.pack-card {
  width: min(260px, 68vw);
  display: grid;
  gap: 8px;
  perspective: 900px;
}

.pack-card.is-compact {
  width: 112px;
}

.pack-card-shell {
  position: relative;
  border-radius: 0;
  aspect-ratio: 63 / 88;
  background: #0a0d10;
  transform-style: preserve-3d;
}

/* overflow:hidden on the same box that rotateY's flattens the 3D context, so the
   front face never comes around — the receipt then looks like a striped back that
   just got fatter. Compact cells don't flip; they still clip art to the box. */
.pack-card.is-compact .pack-card-shell {
  overflow: hidden;
}

.pack-card-shell img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.pack-card-face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
}

.pack-card-front {
  transform: rotateY(180deg);
}

.pack-card-back {
  background:
    repeating-linear-gradient(135deg, #1a1018 0 14px, #2a1822 14px 28px);
  box-shadow: inset 0 0 0 8px #3a2430;
}

.pack-card.is-entering .pack-card-shell {
  animation: pack-flip 640ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}

.pack-card.enter-epic .pack-card-shell,
.pack-card.enter-showcase .pack-card-shell {
  animation-duration: 900ms;
}

/* Battlefields are landscape art (1038x744); a portrait box would crop them top and bottom. */
.pack-card.is-landscape .pack-card-shell {
  aspect-ratio: 88 / 63;
}

.pack-card.is-landscape .pack-card-shell img {
  object-fit: contain;
}

.pack-card.is-landscape:not(.is-compact) {
  width: min(360px, 82vw);
}

.pack-card.is-compact.is-landscape {
  width: 160px;
  grid-column: span 2;
}

/* A revealed card only ever turns over: the shell runs `pack-flip`. It never translates in. The
   card-level entry animation this replaces named a keyframe set that was never defined, so it
   was a dead reference that still suppressed the first paint. */
.pack-card.is-flipped .pack-card-shell {
  transform: rotateY(180deg);
}

.pack-card.is-chase .pack-card-shell {
  box-shadow: 0 0 0 2px var(--accent), 0 12px 28px rgb(245 158 11 / 28%);
}

.pack-card-meta,
.pack-card-price,
.pack-reveal-meta {
  font-size: 12px;
  color: var(--muted);
}

.pack-card-meta strong {
  display: block;
  color: var(--ink);
  font-size: 13px;
}

.pack-overview {
  width: 100%;
  display: grid;
  gap: 28px;
}

/* Lazy sentinel. A carton is 144 packs × 15 cells; mounting them all on the first paint froze
   the tab for seconds. The observer swaps a page in when this scrolls near the viewport. */
.pack-overview-more {
  padding: 14px;
  border: 1px dashed var(--line);
  color: var(--faint);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-align: center;
}

.pack-hits {
  width: 100%;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--panel);
}

.pack-hits header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 10px;
}

.pack-hits header p,
.pack-hits-empty {
  color: var(--muted);
  font-size: 13px;
}

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

.pack-hits .pack-card.is-hit .pack-card-shell {
  box-shadow: 0 0 0 1px var(--accent);
}

.pack-overview-pack header {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}

.pack-overview-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
  gap: 10px;
  /* Landscape battlefields take `grid-column: span 2`; without dense packing they leave a
     hole at the end of the previous row. */
  grid-auto-flow: dense;
}

/* First cell of every pack grid: the booster it came out of, not a pull. */
.pack-card.pack-hero .pack-card-shell {
  box-shadow: inset 0 0 0 1px var(--accent);
  opacity: 0.85;
}

.pack-card.pack-hero .pack-card-meta strong {
  color: var(--accent);
  letter-spacing: 0.1em;
}

.pack-stage-actions {
  display: flex;
  gap: 8px;
}

.pack-card-missing {
  display: grid;
  place-items: center;
  height: 100%;
  padding: 8px;
  text-align: center;
}

@keyframes pack-flip {
  from { transform: rotateY(0deg); }
  to { transform: rotateY(180deg); }
}

/* Reduced motion removes travel, not the result. The JS half skips every delay (pointerdown and
   Enter commit straight through), and this half parks the flap, the tear and the stack at their
   resting pose so nothing moves on the way there. */
@media (prefers-reduced-motion: reduce) {
  .pack-card.is-entering,
  .pack-card.is-entering .pack-card-shell,
  .pack-wrapper-flap,
  .pack-wrapper-body,
  .pack-wrapper-stack,
  .pack-wrapper.is-open .pack-wrapper-flap,
  .pack-wrapper.is-open .pack-wrapper-body,
  .pack-wrapper.is-open .pack-wrapper-stack {
    animation: none;
    transition: none;
  }
  .pack-wrapper-flap,
  .pack-wrapper.is-open .pack-wrapper-flap,
  .pack-wrapper.is-peeling .pack-wrapper-flap {
    transform: none;
  }
  .pack-wrapper-body,
  .pack-wrapper.is-open .pack-wrapper-body,
  .pack-wrapper.is-peeling .pack-wrapper-body {
    clip-path: none;
  }
  .pack-wrapper-stack {
    transform: translateY(6px) scale(0.96);
    opacity: 0.34;
  }
  .pack-wrapper-flap-back {
    filter: none;
  }
  .pack-card.is-entering .pack-card-shell,
  .pack-card.is-flipped .pack-card-shell {
    transform: rotateY(180deg);
  }
}

/* Mobile is a stack, not a squeeze: controls, then the opening, then what came out of it.
   The overview `:has(...)` twin has to be repeated here — it carries an id's specificity, so the
   plain class selector alone would lose to it inside this media query and leave two columns on a
   phone. Idle has no desktop override left to beat, so there is nothing else to list. */
@media (max-width: 860px) {
  .packsim-workspace,
  .packsim-workspace:has(#packStage[data-mode="overview"]) {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 720px) {
  .packsim-head,
  .packsim-controls {
    display: grid;
  }

  .packsim-controls select,
  .packsim-controls input,
  .packsim-controls button {
    width: 100%;
  }

  .pack-ev-table {
    display: block;
    overflow-x: auto;
  }

  /* The table scrolls inside its own box only if the grid items around it may be narrower than it:
     a min-width: auto column took the table's width and pushed the page 48px past a 390 screen
     (53px with the Korean column names, .prd/24 receipt 2026-10-10). */
  .packsim-ev,
  .pack-ev-board,
  .pack-ev-set {
    min-width: 0;
  }
}
