/* ==========================================================================
   pack.css — the sealed booster pack.

   Design: "OneLake". A teal (Fabric) foil wrapper with holographic contour lines
   (an imaginary lake's topography), an oversized, tilted blue crest with
   the badge's two stars, and a small data manifest instead of a sticker.

   Depth: the pack is a real 3D object — a back and two side gussets in a
   preserve-3d shell (depth extends backwards), with the flat front on top — plus "pillow" shading so it looks filled.
   The crimped ends are flat, sealed in the same teal foil.

   All sizes are in cqi (1% of the pack width), so the pack scales as one.
   ========================================================================== */

.pack-wrap {
  --ph: min(64dvh, 640px, calc((100vw - 2 * var(--pad)) / 0.64));  /* pack height */
  --pw: calc(var(--ph) * 0.64);                                      /* pack width  */
  position: relative;
  width: var(--pw);
  height: var(--ph);
  z-index: 30;              /* in front of the cards, which start inside it */
}

/* Soft contact shadow under the floating pack. */
.pack-shadow {
  position: absolute; left: 10%; right: 10%; bottom: -7%;
  height: 8%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgb(0 0 0 / .6), transparent);
  filter: blur(6px);
  animation: shadow-breathe 5s ease-in-out infinite;
}

.pack {
  position: absolute; inset: 0;
  container-type: inline-size;
  cursor: grab;
  touch-action: none;        /* we handle the drag ourselves */
  -webkit-user-select: none; /* dragging to tear must never select the text */
          user-select: none;
  /* Leans a little towards the pull while being torn. */
  transform-origin: 50% 100%;
  rotate: calc(var(--tear) * 2.2deg);
  -webkit-tap-highlight-color: transparent;
  outline-offset: 10px;
}
.pack:active { cursor: grabbing; }

.pack__float {
  position: absolute; inset: 0;
  animation: idle-float 5s ease-in-out infinite;
}

.pack__tilt {
  --rx: 0deg; --ry: 0deg; --mx: 50%; --my: 50%; --hyp: 0;
  --t: 5.5cqi;               /* thickness of the filled pack */
  position: absolute; inset: 0;
}
/* Both groups get the same tilt: the shell in true 3D (preserve-3d), the
   front as a flat 2D layer painted on top of it. */
.pack__shell, .pack__front {
  position: absolute; inset: 0;
  transform: perspective(1100px) rotateX(var(--rx)) rotateY(var(--ry));
}
.pack__shell { transform-style: preserve-3d; }

/* Shared zig-zag edges: jagged tear line on top, crimp teeth at the bottom. */
.pack__body, .pack__back {
  --zt: 2.5cqi;    /* same tooth as the strip's torn edge */
  --zb: 3.2cqi;
  -webkit-mask:
    conic-gradient(from 135deg at top, #0000, #000 1deg 89deg, #0000 90deg) top / var(--zt) calc(var(--zt) / 2) repeat-x,
    linear-gradient(#000 0 0) 0 calc(var(--zt) / 2) / 100% calc(100% - var(--zt) / 2 - var(--zb) / 2) no-repeat,
    conic-gradient(from -45deg at bottom, #0000, #000 1deg 89deg, #0000 90deg) bottom / var(--zb) calc(var(--zb) / 2) repeat-x;
          mask:
    conic-gradient(from 135deg at top, #0000, #000 1deg 89deg, #0000 90deg) top / var(--zt) calc(var(--zt) / 2) repeat-x,
    linear-gradient(#000 0 0) 0 calc(var(--zt) / 2) / 100% calc(100% - var(--zt) / 2 - var(--zb) / 2) no-repeat,
    conic-gradient(from -45deg at bottom, #0000, #000 1deg 89deg, #0000 90deg) bottom / var(--zb) calc(var(--zb) / 2) repeat-x;
}

/* ── 3D shell ────────────────────────────────────────────────────────── */

.pack__back {
  position: absolute; left: 0; right: 0; top: 10%; bottom: 0;
  transform: translateZ(calc(var(--t) * -1)) rotateY(180deg);
  background: linear-gradient(170deg, #19776e, #0f4d44 60%, #072a25);
}

/* Side gussets: the pack is thickest in the middle and pinched flat at the
   crimps, so each side is a tall, tapered sliver turned 90° into depth. */
.pack__side {
  position: absolute; top: 13%; bottom: 6%;
  width: var(--t);
  border-radius: 50% / 9%;
  background:
    linear-gradient(180deg, rgb(0 0 0 / .35), transparent 12% 88%, rgb(0 0 0 / .35)),
    linear-gradient(90deg, #08302a, #1f8576 50%, #08302a);
}
.pack__side--l { left: calc(var(--t) / -2); transform: translateZ(calc(var(--t) / -2)) rotateY(-90deg); }
.pack__side--r { right: calc(var(--t) / -2); transform: translateZ(calc(var(--t) / -2)) rotateY(90deg); }

/* ── Front ───────────────────────────────────────────────────────────── */

.pack__body {
  position: absolute;
  left: 0; right: 0; top: 10%; bottom: 0;
  overflow: hidden;
  isolation: isolate;
  /* The front stays at z = 0 (depth goes backwards) so it rasterises at full
     resolution; a z offset makes Chrome render it soft on high-DPI phones. */
}

.pack__bg {
  position: absolute; inset: 0;
  background:
    radial-gradient(60% 40% at 30% 30%, rgb(116 234 194 / .22), transparent 70%),
    linear-gradient(172deg, #2b9a8a 0%, #19776e 26%, #136458 52%, #0f4d44 76%, #08302a 100%);
}

/* OneLake: contour lines (over both the teal and the blue shield) from assets/topo.svg used as a mask over a soft
   rainbow that slides with the light — holographic lines, nothing else. */
.pack__topo {
  position: absolute; inset: 0;
  /* Lines are strongest around the "lake" (top) and fade behind the type. */
  -webkit-mask:
    url("../assets/topo.svg") center / cover no-repeat,
    linear-gradient(180deg, #000 0 38%, rgb(0 0 0 / .28) 52% 100%);
  -webkit-mask-composite: source-in;
          mask:
    url("../assets/topo.svg") center / cover no-repeat intersect,
    linear-gradient(180deg, #000 0 38%, rgb(0 0 0 / .28) 52% 100%);
  background-image:
    linear-gradient(rgb(255 255 255 / .45), rgb(255 255 255 / .45)),
    repeating-linear-gradient(115deg, #8fd8ff 0%, #b9a7ff 6%, #ffc4e6 12%, #fff1b8 18%, #b6ffd9 24%, #8fd8ff 30%);
  background-size: 100% 100%, 260% 260%;
  background-position: 0 0, var(--mx) var(--my);
  opacity: calc(.26 + var(--hyp) * .34);
}

/* Crest: the shield is wider than the pack, rotated, and cropped by the
   wrapper's edges, so it reads as artwork rather than a logo. */
.pack__crest {
  position: absolute;
  width: 84cqi;
  left: 30cqi; top: -38cqi;
  rotate: -16deg;
  overflow: visible;
  filter: drop-shadow(-1.5cqi 2.5cqi 4cqi rgb(0 0 0 / .45));
}
.crest__shield {
  fill: url(#crestFill);
  stroke: rgb(255 255 255 / .9);
  stroke-width: 2.2;
}
.crest__inner {
  fill: none;
  stroke: rgb(255 255 255 / .35);
  stroke-width: .9;
  stroke-dasharray: 3 2.4;
}
.crest__star {
  fill: #fff;
  filter: drop-shadow(0 2px 3px rgb(0 20 60 / .45));
}

/* Typography block. Positions are in cqi = the SVG's units. */
.pack__topo { z-index: 1; }
.pack__content { position: absolute; inset: 0; z-index: 2; }

.pack__code {
  position: absolute; left: 7cqi; top: 79cqi;
  margin: 0;
  font: 700 21.5cqi/.86 var(--sans);
  letter-spacing: -.045em;
  color: #fff;
  text-shadow: 0 .5cqi 0 rgb(0 0 0 / .45), 0 2cqi 5cqi rgb(0 0 0 / .35);
}
.pack__name {
  position: absolute; left: 7.6cqi; top: 99.5cqi;
  margin: 0;
  font: 500 6.2cqi/1 var(--sans);
  letter-spacing: -.01em;
  color: #dff7f1;
}

/* The manifest: a tiny two-row table, like a dataset's metadata. */
.pack__manifest {
  position: absolute; left: 7.6cqi; right: 7.6cqi; top: 110.5cqi;
  margin: 0;
  padding: .2cqi 3cqi;
  border-radius: 2cqi;
  font: 400 3.2cqi/1 var(--mono);
  /* a frosted blue panel, echoing the shield */
  background: linear-gradient(180deg, rgb(0 100 181 / .38), rgb(0 32 80 / .5));
  box-shadow: inset 0 0 0 .25cqi rgb(255 255 255 / .22), 0 1.5cqi 4cqi rgb(0 10 35 / .35);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.pack__manifest div {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 1.7cqi 0 1.5cqi;
}
.pack__manifest div + div { border-top: .2cqi solid rgb(255 255 255 / .2); }
.pack__manifest dt { color: #b9d3ee; letter-spacing: .04em; }
.pack__manifest dd { margin: 0; color: #fff; font-weight: 500; letter-spacing: .12em; text-transform: uppercase; }

/* Pillow shading: darker towards the edges, a seam above the flat crimp,
   and a vertical specular band that slides with the light. */
.pack__pillow {
  position: absolute; inset: 0; z-index: 3;
  pointer-events: none;
  background:
    linear-gradient(100deg, transparent calc(var(--mx) - 24%), rgb(255 255 255 / .13) var(--mx), transparent calc(var(--mx) + 24%)),
    linear-gradient(90deg, rgb(0 0 0 / .55) 0%, rgb(0 0 0 / .16) 5%, transparent 15% 85%, rgb(0 0 0 / .16) 95%, rgb(0 0 0 / .55) 100%),
    linear-gradient(180deg, rgb(0 0 0 / .40) 0%, transparent 7% 84%, rgb(0 0 0 / .4) 91.6%, transparent 92.4%);
}

/* ── Crimped, ribbed seals in the pack's own teal ────────────────────── */

.pack__crimp {
  position: absolute; left: 0; right: 0;
  background:
    repeating-linear-gradient(90deg, rgb(255 255 255 / .2) 0 .28cqi, rgb(0 0 0 / .16) .28cqi .8cqi, transparent .8cqi 1.4cqi),
    linear-gradient(180deg, #51bcab 0%, #24907f 38%, #146a5e 100%);
}
.pack__crimp--bottom {
  bottom: 0; height: 7.8%; z-index: 2;
  background:
    repeating-linear-gradient(90deg, rgb(255 255 255 / .2) 0 .28cqi, rgb(0 0 0 / .16) .28cqi .8cqi, transparent .8cqi 1.4cqi),
    linear-gradient(180deg, #0f4d44 0%, #146a5e 45%, #3fa595 100%);
}

/* ── Tear strip ──────────────────────────────────────────────────────── */

.pack__strip {
  --z: 3.3333cqi;  /* crimp tooth (3 per slice, so teeth line up at joints) */
  --zt: 2.5cqi;    /* torn-edge tooth (4 per slice; matches the body)     */
  position: absolute; left: 0; right: 0; top: 0;
  height: 11.2%;               /* overlaps the body's jagged edge a little */
  filter: drop-shadow(0 calc(var(--tear) * 1.6cqi) calc(var(--tear) * 1.8cqi) rgb(0 0 0 / .45));
}

/* One slice of the strip. The root sits at the right end; every child sits
   just left of its parent and pivots on their shared bottom corner (so
   slices overlap instead of opening gaps), bending once the tear point has
   passed that joint. */
.seg {
  --amt: clamp(0, calc(var(--tear) * var(--n) - var(--i) - 1), 1);
  position: absolute; top: 0; bottom: 0;
  width: 100%;
  right: 100%;
  transform-origin: 100% 100%;
  rotate: calc(var(--amt) * 4deg);     /* clockwise: the free end peels up */
}
.seg--root { width: calc(100% / var(--n)); right: 0; }
.seg__skin { position: absolute; inset: 0; }
/* Curled slices catch more light. */
.seg__skin::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgb(255 255 255 / .28), rgb(255 255 255 / .06));
  opacity: var(--amt);
}

.seg__skin {
  /* Crimp teeth on top, a finer torn edge at the bottom. */
  -webkit-mask:
    conic-gradient(from 135deg at top, #0000, #000 1deg 89deg, #0000 90deg) top / var(--z) calc(var(--z) / 2) repeat-x,
    linear-gradient(#000 0 0) 0 calc(var(--z) / 2) / 100% calc(100% - var(--z) / 2 - var(--zt) / 2) no-repeat,
    conic-gradient(from -45deg at bottom, #0000, #000 1deg 89deg, #0000 90deg) bottom / var(--zt) calc(var(--zt) / 2) repeat-x;
          mask:
    conic-gradient(from 135deg at top, #0000, #000 1deg 89deg, #0000 90deg) top / var(--z) calc(var(--z) / 2) repeat-x,
    linear-gradient(#000 0 0) 0 calc(var(--z) / 2) / 100% calc(100% - var(--z) / 2 - var(--zt) / 2) no-repeat,
    conic-gradient(from -45deg at bottom, #0000, #000 1deg 89deg, #0000 90deg) bottom / var(--zt) calc(var(--zt) / 2) repeat-x;
}

/* Small notch on the left: the classic "start tearing here" cue. */
.pack__notch {
  position: absolute; left: 0; bottom: 18%;
  width: 2.6cqi; height: 2.6cqi;
  z-index: 1;
  opacity: max(0, 1 - var(--tear) * 12);   /* the cut opens up as the tear starts */
  background: var(--bg);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}
/* Perforation along the tear line. */
.pack__tearline {
  position: absolute; left: calc(var(--tear) * 100%); right: 0; bottom: 0;
  height: .5cqi;
  background: repeating-linear-gradient(90deg, rgb(0 25 70 / .6) 0 1.2cqi, transparent 1.2cqi 2.1cqi);
}
/* A small bright point where the foil is tearing. */
.pack__tearline::after {
  content: "";
  position: absolute; top: -1cqi;
  left: calc(var(--tear) * 100% - 1.2cqi);
  width: 2.4cqi; height: 2.4cqi;
  border-radius: 50%;
  background: radial-gradient(circle, #fff, rgb(183 255 240 / .8) 40%, transparent 70%);
  box-shadow: 0 0 2.5cqi 1cqi rgb(116 234 194 / .55);
  opacity: calc(min(1, var(--tear) * 10) * min(1, (1 - var(--tear)) * 10));
}

/* ── Hint ────────────────────────────────────────────────────────────── */

.hint {
  position: absolute; left: 0; bottom: 100%;
  margin: 0 0 clamp(10px, 2.2vmin, 22px);
  font: 500 clamp(12px, 1.1vmin + 7px, 16px)/1 var(--mono);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #cfe3f8;
  white-space: nowrap;
  pointer-events: none;
  -webkit-user-select: none;
          user-select: none;
}
.hint__arrow { display: inline-block; animation: nudge 1.4s ease-in-out infinite; color: #74eac2; }

/* ── Keyframes ───────────────────────────────────────────────────────── */

@keyframes idle-float {
  0%, 100% { translate: 0 0;      rotate: -1.2deg; }
  50%      { translate: 0 -2.2cqi; rotate: 1.2deg; }
}
@keyframes shadow-breathe {
  0%, 100% { scale: 1;   opacity: 1; }
  50%      { scale: .86; opacity: .7; }
}
@keyframes nudge {
  0%, 100% { translate: 0 0; }
  50%      { translate: .45em 0; }
}

/* Reduced motion: a still pack. */
.is-reduced .pack__float, .is-reduced .pack-shadow, .is-reduced .hint__arrow { animation: none; }
