/* Rare drop celebration: the big loot beam and the item card in front of it (built by fx.js inside #fx).
   The card takes the page's colours from the tokens in style.css; the beam's golds are fixed (it is a golden beam
   for every drop, like the game's default loot beam). No image files: everything is gradients. */

/* ---------- overlay ---------- */
/* fx.js only sets class names on #fx: tier-rare|mega|pet (trim colour), size-1..4 (how big the beam is),
   flash (one white flash), calm (reduced motion). The beam itself is gold for every tier, like the game's. */
.fx {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center; padding: 16px; cursor: pointer; overflow: hidden;
  background: rgb(2 7 11 / .72);
  animation: fxIn .25s ease-out;
  --tier: #ffc94d;
  --w: 120px; --core: 14px; --k: 1;          /* column and core width; --k shrinks every beam on phones */
  --W: calc(var(--w) * var(--k));
  --foot: max(60px, 11%, calc(var(--W) * .42));   /* how far above the bottom edge the beam stands */
  --reach: .1;                               /* how bright the column still is at the top of the window */
  --rise: linear-gradient(to top, transparent, #000 7%, #000 24%, rgb(0 0 0 / var(--reach)));
}
.fx[hidden] { display: none; }
.fx.out { animation: fxOut .32s ease-in forwards; }
.fx.tier-mega { --tier: #ff8a1f; }
.fx.tier-pet  { --tier: #5dff8f; }
.fx.size-2 { --w: 160px; --core: 20px; --reach: .5; }
.fx.size-3 { --w: 200px; --core: 28px; --reach: .68; }
.fx.size-4 { --w: 260px; --core: 36px; --reach: .85; }
.fx-canvas { position: fixed; inset: 0; width: 100vw; height: 100vh; pointer-events: none; z-index: 70; }

/* ---------- the loot beam ---------- */
/* Back to front: a glow over the whole window, the ground (light pool, rune disc, ring) and the beam (side flames,
   gold column, rising motes, white core). Ground and beam are zero-width boxes on the centre line that end at the
   foot, so every part is placed from that one spot. Only transform and opacity are animated. */
.fx-glow, .fx-ground, .fx-beam, .fx-flash { position: absolute; pointer-events: none; }
.fx-ground i, .fx-beam i { position: absolute; }
.fx-glow {
  inset: 0;
  background:
    radial-gradient(ellipse calc(var(--W) * 2.4) 44% at 50% 46%, rgb(255 186 60 / .3), transparent 72%),
    radial-gradient(ellipse calc(var(--W) * 3.6) 62% at 50% calc(100% - var(--foot)), color-mix(in srgb, var(--tier) 34%, transparent), transparent 70%);
  animation: fxGlow 1.2s ease-in-out infinite alternate;
}
.fx-ground, .fx-beam { left: 50%; top: 0; bottom: var(--foot); width: 0; }
.fx-ground { animation: fxIn .15s ease-out both; }
.fx-beam { transform-origin: 50% 100%; animation: fxRise .32s cubic-bezier(.2, .9, .3, 1) both; }

.fx-pool {
  left: calc(var(--W) * -3); width: calc(var(--W) * 6); bottom: calc(var(--W) * -.55); height: calc(var(--W) * 1.1);
  background: radial-gradient(closest-side, rgb(255 186 60 / .42), transparent);
}
.fx-ring, .fx-shock {
  left: calc(var(--W) * -1.05); width: calc(var(--W) * 2.1); bottom: calc(var(--W) * -.273); height: calc(var(--W) * .546);
  border-radius: 50%;
}
.fx-ring {
  border: 2px solid rgb(254 222 122 / .9);
  box-shadow: 0 0 16px color-mix(in srgb, var(--tier) 75%, transparent), inset 0 0 14px rgb(254 222 122 / .45);
  animation: fxRing 1.2s ease-in-out infinite alternate;
}
.fx.size-2 .fx-ring { background: radial-gradient(closest-side, rgb(255 242 173 / .3), rgb(255 210 125 / .1) 70%, transparent); }
/* One ring racing outward along the ground when the biggest beam lands. */
.fx-shock { display: none; opacity: 0; border: 3px solid rgb(255 246 216 / .9); animation: fxShock .9s ease-out .12s both; }
.fx.size-4 .fx-shock { display: block; }

/* The rune disc: a circle laid flat by scaleY, turning slowly. Two rings of marks between two gold lines. */
.fx-disc {
  display: none; left: calc(var(--W) * -1.4); width: calc(var(--W) * 2.8); bottom: calc(var(--W) * -1.4); height: calc(var(--W) * 2.8);
  transform: scaleY(.26);
}
.fx.size-3 .fx-disc, .fx.size-4 .fx-disc { display: block; }
/* With the disc around it, the ring is smaller and sits inside the disc's inner line. */
.fx.size-3 .fx-ring, .fx.size-4 .fx-ring { left: calc(var(--W) * -.7); width: calc(var(--W) * 1.4); bottom: calc(var(--W) * -.182); height: calc(var(--W) * .364); }
.fx-disc i {
  inset: 0; border-radius: 50%; will-change: transform;
  background: radial-gradient(closest-side, rgb(255 186 60 / .26) 52%, transparent 53% 55%, rgb(255 214 110 / .95) 56% 59%,
    transparent 60% 90%, rgb(255 214 110 / .98) 91% 96%, transparent 97%);
  animation: fxTurn 18s linear infinite;
}
.fx-disc i::before, .fx-disc i::after { content: ""; position: absolute; inset: 0; border-radius: 50%; }
.fx-disc i::before {
  background:
    repeating-conic-gradient(from 3deg, rgb(255 214 110 / .95) 0 5deg, transparent 5deg 9deg, rgb(255 214 110 / .95) 9deg 10.5deg, transparent 10.5deg 20deg);
  -webkit-mask-image: radial-gradient(closest-side, transparent 73%, #000 74% 87%, transparent 88%);
          mask-image: radial-gradient(closest-side, transparent 73%, #000 74% 87%, transparent 88%);
}
.fx-disc i::after {
  background: repeating-conic-gradient(rgb(240 176 60 / .95) 0 2deg, transparent 2deg 7.5deg);
  -webkit-mask-image: radial-gradient(closest-side, transparent 62%, #000 63% 70%, transparent 71%);
          mask-image: radial-gradient(closest-side, transparent 62%, #000 63% 70%, transparent 71%);
}

/* Side flames next to the foot: two for size 3, four for size 4. Their base fades out so it has no flat edge. */
.fx-spike {
  display: none; bottom: calc(var(--W) * -.1); width: calc(var(--W) * .5); height: 36%; transform-origin: 50% 100%; will-change: transform, opacity;
  background: radial-gradient(ellipse 50% 100% at 50% 100%, rgb(255 251 230 / .95), rgb(255 205 80 / .7) 36%, rgb(255 170 30 / 0) 70%);
  -webkit-mask-image: linear-gradient(to top, transparent, #000 20%); mask-image: linear-gradient(to top, transparent, #000 20%);
  animation: fxLick .9s ease-in-out infinite alternate;
}
.fx.size-3 .fx-spike.a, .fx.size-3 .fx-spike.b, .fx.size-4 .fx-spike { display: block; }
.fx-spike.a { left: calc(var(--W) * -1.3); --tilt: -3deg; }
.fx-spike.b { left: calc(var(--W) * .8); --tilt: 3deg; animation-duration: 1.15s; }
.fx-spike.c { left: calc(var(--W) * -1.5); --tilt: -7deg; height: 22%; animation-duration: .7s; }
.fx-spike.d { left: calc(var(--W) * 1); --tilt: 7deg; height: 22%; animation-duration: 1s; }
.fx.size-4 .fx-spike.a { left: calc(var(--W) * -1.03); height: 48%; }
.fx.size-4 .fx-spike.b { left: calc(var(--W) * .53); height: 48%; }

/* The column: a wide soft halo with the gold beam inside it, brightest at the foot. It breathes. */
.fx-col {
  left: calc(var(--W) * -1.3); width: calc(var(--W) * 2.6); top: 0; bottom: calc(var(--W) * -.3); will-change: transform, opacity;
  background:
    linear-gradient(90deg, transparent 30%, rgb(255 170 30 / .38) 36%, rgb(255 200 61 / .82) 43%, rgb(255 236 150 / .96) 47.5%, #fffbe6 50%, rgb(255 236 150 / .96) 52.5%, rgb(255 200 61 / .82) 57%, rgb(255 170 30 / .38) 64%, transparent 70%),
    linear-gradient(90deg, transparent, rgb(255 176 40 / .36) 50%, transparent);
  -webkit-mask-image: var(--rise); mask-image: var(--rise);
  animation: fxBreathe 1.2s ease-in-out infinite alternate;
}
/* Small lights climbing the beam (sizes 2-4). The inner strip is one tile taller than the box and slides up by a tile. */
.fx-motes {
  display: none; left: calc(var(--W) * -.7); width: calc(var(--W) * 1.4); top: 0; bottom: 0; overflow: hidden;
  -webkit-mask-image: linear-gradient(to top, transparent 3%, #000 16%, #000 55%, transparent 96%);
          mask-image: linear-gradient(to top, transparent 3%, #000 16%, #000 55%, transparent 96%);
}
.fx.size-2 .fx-motes, .fx.size-3 .fx-motes, .fx.size-4 .fx-motes { display: block; }
.fx-motes i {
  inset: 0 0 -260px; will-change: transform;
  --mote: #fff 0 1.5px, rgb(255 242 173 / .85) 2.5px, transparent 4.5px;
  background:
    radial-gradient(circle at 18% 12px, var(--mote)), radial-gradient(circle at 40% 44px, var(--mote)),
    radial-gradient(circle at 66% 70px, var(--mote)), radial-gradient(circle at 84% 98px, var(--mote)),
    radial-gradient(circle at 70% 128px, var(--mote)), radial-gradient(circle at 44% 152px, var(--mote)),
    radial-gradient(circle at 22% 178px, var(--mote)), radial-gradient(circle at 12% 206px, var(--mote)),
    radial-gradient(circle at 34% 232px, var(--mote)), radial-gradient(circle at 58% 250px, var(--mote));
  background-size: 100% 260px;
  animation: fxMotes 2.6s linear infinite;
}
/* The white-hot core, a flame around its lower part and the bright bulb at the foot. */
.fx-core {
  left: calc(var(--W) * -.8); width: calc(var(--W) * 1.6); top: 0; bottom: calc(var(--W) * -.3);
  background:
    radial-gradient(closest-side, #fff 30%, rgb(255 238 160 / .92) 55%, rgb(255 196 64 / 0)) center bottom / calc(var(--W) * 1.5) calc(var(--W) * 2.2) no-repeat,
    radial-gradient(ellipse 50% 100% at 50% 100%, #fff, rgb(255 238 160 / .85) 34%, rgb(255 200 61 / 0) 70%) center bottom / var(--W) 58% no-repeat,
    linear-gradient(90deg, transparent, #fff 35%, #fff 65%, transparent) center / calc(var(--core) * var(--k)) 100% no-repeat;
  -webkit-mask-image: var(--rise); mask-image: var(--rise);
}
.fx-flash { inset: 0; opacity: 0; background: radial-gradient(circle, #fff, rgb(255 246 216 / .92) 28%, rgb(255 210 125 / 0) 76%); }
.fx.flash .fx-flash { animation: fxFlash .6s ease-out; }

/* ---------- the item card, in front of the beam ---------- */
/* A game window: charcoal body you can just see the beam through, brass double-line frame, the tier in big capitals. */
.fx-card {
  position: relative; z-index: 1; isolation: isolate; text-align: center;
  width: min(92vw, 380px); max-height: calc(100dvh - 32px); overflow: hidden auto;
  padding: 22px 18px 0; border-radius: 2px;
  background: color-mix(in srgb, var(--panel) 94%, transparent); color: var(--text);
  border: 1px solid color-mix(in srgb, var(--tier) 65%, #745d39);
  box-shadow: 0 0 0 1px #0f0e0c, inset 0 0 0 1px #110f0d, inset 0 0 0 2px rgb(164 138 91 / .4),
    0 0 46px color-mix(in srgb, var(--tier) 55%, transparent), inset 0 0 46px color-mix(in srgb, var(--tier) 12%, transparent);
  animation: fxPop .45s cubic-bezier(.2, 1.4, .4, 1);
}
.fx-card::before {                 /* the beam showing through the card, behind its contents */
  content: ""; position: absolute; z-index: -1; top: 0; bottom: 0; left: 50%; width: var(--W); margin-left: calc(var(--W) / -2);
  pointer-events: none;
  background: linear-gradient(90deg, transparent, rgb(255 221 144 / .2) 38%, rgb(255 242 173 / .26) 50%, rgb(255 221 144 / .2) 62%, transparent);
}
.fx-x { position: absolute; top: 5px; right: 6px; width: 30px; height: 30px; border: 0; border-radius: 2px;
  background: none; color: var(--muted); font-size: 1.3rem; line-height: 1; cursor: pointer; }
.fx-x:hover { color: var(--text); }
.fx-x:focus-visible { outline: 2px solid var(--tier); outline-offset: 1px; }
.fx-title {
  font-family: var(--font-head, "Palatino Linotype", Palatino, "Book Antiqua", "Noto Serif", Georgia, serif);
  font-size: clamp(1.6rem, 8.4vw, 2.3rem); line-height: 1.05; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  font-variant-numeric: lining-nums; text-wrap: balance;
  color: var(--tier); text-shadow: 0 0 18px color-mix(in srgb, var(--tier) 70%, transparent), 2px 2px 0 #000;
  animation: fxPulse .8s ease-in-out infinite alternate;
}
.fx-title::after {                 /* a thin rule under the title, fading out at both ends */
  content: ""; display: block; height: 1px; margin: 10px 12% 0;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--tier) 80%, transparent), transparent);
}
.fx-icon { position: relative; height: clamp(88px, 18dvh, 150px); margin: 10px auto 6px; display: grid; grid-template-rows: minmax(0, 1fr); place-items: center; }
.fx-icon::before {                 /* light behind the picture, so no filter is needed on it */
  content: ""; position: absolute; left: 50%; top: 50%; width: 190px; height: 190px; margin: -95px 0 0 -95px; pointer-events: none;
  background: radial-gradient(closest-side, rgb(255 242 173 / .4), rgb(255 210 125 / .16) 55%, transparent);
}
/* The picture bobs 5px each way, so it is kept that much shorter than its box. Inventory sprites are small: twice their size. */
.fx-icon img { position: relative; width: 72px; height: auto; max-height: calc(100% - 10px); object-fit: contain;
  animation: fxFloat 1.6s ease-in-out infinite alternate; }
.fx-icon img.detail { width: auto; max-width: 150px; }
.fx-name { font-size: 1.3rem; font-weight: 800; color: #fff; text-shadow: 1px 1px 0 #000; overflow-wrap: anywhere; text-wrap: balance; }
.fx-meta { color: var(--text); font-size: .9rem; margin: 2px 0 14px; font-variant-numeric: tabular-nums; }
.fx-meta .ico { width: 18px; height: 18px; object-fit: contain; vertical-align: -4px; margin-right: .2rem; }
.fx-note { margin: -6px 0 12px; font-size: .82rem; font-weight: 700; color: #fff; opacity: .85; }
/* The batch's other big drops: small item slots outlined in their tier's colour. */
.fx-also { border-top: 1px solid var(--border); margin: 0 -18px; padding: 9px 12px 12px; }
.fx-also-label { font-size: .68rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin-bottom: 6px; }
.fx-also-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 5px; }
.fx-mini {
  position: relative; width: 40px; height: 38px; display: grid; place-items: center; border-radius: 2px; background: var(--slot-bg);
  border: 1px solid color-mix(in srgb, var(--mini, #ffc94d) 70%, transparent);
  box-shadow: 0 0 8px color-mix(in srgb, var(--mini, #ffc94d) 35%, transparent);
}
.fx-mini.tier-mega { --mini: #ff8a1f; }
.fx-mini.tier-pet { --mini: #5dff8f; }
.fx-mini.more { --mini: var(--border); color: var(--text); font-size: .8rem; font-weight: 800; }
.fx-mini img { max-width: 34px; max-height: 32px; }
.fx-mini-n { position: absolute; top: 1px; left: 3px; font: 16px/1 'RuneScape Small', Verdana, sans-serif; color: #ffff00; text-shadow: 1px 1px 0 #000; }
.fx-off { display: flex; justify-content: center; align-items: center; gap: .35rem; margin: 0 0 10px; font-size: .78rem; color: var(--muted); cursor: pointer; }
.fx-off input { accent-color: var(--tier); margin: 0; }
/* The bar that empties while the card is up: it shrinks from the right, so no layout while it runs. */
.fx-bar { height: 3px; margin: 0 -18px; background: rgb(255 255 255 / .08); }
.fx-bar i { display: block; height: 100%; background: var(--tier); transform-origin: 0 50%; animation: fxDrain 4s linear forwards; }
/* Buttons of a card that waits for the player (auto-kill paused). */
.fx-actions { display: flex; gap: .5rem; justify-content: center; margin: .2rem 0 16px; }
.fx-btn {
  font: inherit; font-weight: 700; cursor: pointer; padding: .5rem 1rem; border-radius: 2px;
  background: rgb(255 255 255 / .06); color: var(--text); border: 1px solid rgb(255 255 255 / .2);
}
.fx-btn.primary { background: var(--tier); color: #1a1208; border-color: var(--tier); }
.fx-btn:hover { filter: brightness(1.12); }
.fx-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* ---------- page shake (fx.js puts fx-shake on <body> for half a second) ---------- */
body.fx-shake .layout, body.fx-shake .topbar { animation: fxShake .5s; }
body.fx-shake { overflow-x: clip; }   /* the shake must not open a sideways scroll */

@keyframes fxIn      { from { opacity: 0; } to { opacity: 1; } }
@keyframes fxOut     { to { opacity: 0; } }
@keyframes fxGlow    { from { opacity: .72; } to { opacity: 1; } }
@keyframes fxRise    { from { transform: scaleY(0); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes fxBreathe { from { transform: scaleX(1); opacity: 1; } to { transform: scaleX(.8); opacity: .7; } }
@keyframes fxRing    { from { opacity: .6; } to { opacity: 1; } }
@keyframes fxShock   { from { transform: scale(.4); opacity: .9; } to { transform: scale(3.2); opacity: 0; } }
@keyframes fxTurn    { to { transform: rotate(360deg); } }
@keyframes fxLick    { from { transform: rotate(var(--tilt)) scaleY(1); opacity: .95; } to { transform: rotate(var(--tilt)) scaleY(.78); opacity: .6; } }
@keyframes fxMotes   { to { transform: translateY(-260px); } }
@keyframes fxFlash   { 0% { opacity: 0; } 22% { opacity: .8; } 100% { opacity: 0; } }
@keyframes fxPop     { from { transform: scale(.3) rotate(-6deg); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes fxPulse   { from { transform: scale(1); } to { transform: scale(1.05); } }
@keyframes fxFloat   { from { transform: translateY(-5px); } to { transform: translateY(5px); } }
@keyframes fxDrain   { from { transform: scaleX(1); } to { transform: scaleX(0); } }
@keyframes fxShake   {
  0%, 100% { transform: none; } 20% { transform: translate(-9px, 4px); } 40% { transform: translate(8px, -5px); }
  60% { transform: translate(-6px, 3px); } 80% { transform: translate(4px, -2px); }
}

/* ---------- phones ---------- */
@media (max-width: 600px) {
  .fx { --k: .62; }
  .fx-x { width: 40px; height: 40px; top: 0; right: 0; }
}
@media (max-height: 520px) {       /* phones on their side: a small title and picture, no "Also looted" */
  .fx { --foot: 34px; }
  .fx-card { padding-top: 12px; }
  .fx-title { font-size: 1.4rem; }
  .fx-icon { height: 72px; margin: 4px auto 2px; }
  .fx-also { display: none; }
}

/* ---------- reduced motion: a still beam and a still card, no flash, no shake ---------- */
/* fx.js adds .calm and skips the flash, the shake and the sparks; the media query is the safety net.
   The bar does not drain (the card still closes on time). */
.fx.calm *, .fx.calm *::before, .fx.calm *::after { animation: none !important; }
@media (prefers-reduced-motion: reduce) {
  .fx *, .fx *::before, .fx *::after { animation: none !important; }
  body.fx-shake .layout, body.fx-shake .topbar { animation: none; }
}
