/* Engagement layer: frames, prize envelopes, quests, streak, leagues, shop. See docs/ENGAGEMENT.md and docs/DESIGN.md. */
:root { --r-common: #6B6152; --r-rare: #2F5D8A; --r-epic: #8A2F5E; --r-legendary: #8F620A; } /* rarity names are text: ≥4.5:1 */
:root[data-theme="dark"], .stage, .party, .pad { --r-common: #A39883; --r-rare: #7FA8D6; --r-epic: #D681AE; --r-legendary: #F0B33A; }
.rarity-common { --rc: var(--r-common); } .rarity-rare { --rc: var(--r-rare); } .rarity-epic { --rc: var(--r-epic); } .rarity-legendary { --rc: var(--r-legendary); }
.rtext { color: var(--rc); font-weight: 700; }

/* ---- avatar frames: a printed ring just outside the avatar ---- */
.avatar[data-frame]::after {
  content: ""; position: absolute; inset: calc(var(--size) * -.1); border-radius: 50%; padding: calc(var(--size) * .065 + 1px); background: var(--fr); pointer-events: none;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
.avatar[data-frame="frame_mint"] { --fr: #3E9C7A; }
.avatar[data-frame="frame_sunset"] { --fr: repeating-conic-gradient(#C8381F 0 30deg, #E9A23B 0 60deg); }
.avatar[data-frame="frame_neon"] { --fr: repeating-conic-gradient(var(--ink) 0 10deg, transparent 0 20deg); }
.avatar[data-frame="frame_gold"] { --fr: conic-gradient(#F3D27A, #A87100, #F3D27A, #8A5C00, #F3D27A); }
.avatar[data-frame="frame_glacier"] { --fr: conic-gradient(#E8F1F5, #6E9BB8, #E8F1F5, #4F7A96, #E8F1F5); }
.avatar[data-frame="frame_inferno"] { --fr: conic-gradient(from var(--spin), #C8381F, #E9A23B, #C8381F, #5A1408, #C8381F); animation: spin 5s linear infinite; }
.avatar[data-frame="frame_cosmic"] { --fr: conic-gradient(from var(--spin), #1A1712, #2F5D8A, #F1EADB, #8A2F5E, #1A1712); animation: spin 6s linear infinite; }
.avatar[data-frame="frame_royal"] { --fr: repeating-conic-gradient(#C98A12 0 15deg, #8A2F5E 0 30deg); }
.avatar[data-frame="ref_frame_friendship"] { --fr: repeating-conic-gradient(#C8381F 0 18deg, #F2ECDF 0 24deg, #F0B33A 0 42deg, #F2ECDF 0 48deg); }
.rarity-friend { --rc: var(--signal); }
.avatar[data-frame="frame_ocean"] { --fr: repeating-conic-gradient(#2F5D8A 0 20deg, #7FA8D6 0 40deg, #E8F1F5 0 45deg); }
.avatar[data-frame="frame_meadow"] { --fr: repeating-conic-gradient(#3E9C7A 0 24deg, #9CCB6B 0 36deg, #F0B33A 0 40deg); }
.avatar[data-frame="frame_candy"] { --fr: repeating-conic-gradient(#E89AAE 0 12deg, #F2ECDF 0 24deg); }
.avatar[data-frame="frame_checker"] { --fr: repeating-conic-gradient(#1A1712 0 15deg, #F2ECDF 0 30deg); }
.avatar[data-frame="frame_aurora"] { --fr: conic-gradient(from var(--spin), #3E9C7A, #7FA8D6, #8A2F5E, #3E9C7A); animation: spin 7s linear infinite; }
.avatar[data-frame="frame_marble"] { --fr: conic-gradient(#F2ECDF, #CFC6B5, #F2ECDF 30%, #A39883 34%, #F2ECDF 40%, #E2DACB 70%, #8C8478 73%, #F2ECDF); }
.avatar[data-frame="frame_circuit"] { --fr: repeating-conic-gradient(#1F4D3A 0 8deg, #3E9C7A 0 10deg, #1F4D3A 0 18deg, #F0B33A 0 20deg); }
.avatar[data-frame="frame_supernova"] { --fr: conic-gradient(from var(--spin), #FFF8E1, #F0B33A, #C8381F, #4B3C8C, #1A1712, #4B3C8C, #C8381F, #F0B33A, #FFF8E1); animation: spin 3s linear infinite; }
.avatar[data-frame="frame_prism"] { --fr: conic-gradient(from var(--spin), #E8505B, #F0B33A, #F2E35C, #3E9C7A, #2F8AD6, #8A5BD6, #E8505B); animation: spin 4s linear infinite; }
.avatar[data-frame="frame_eclipse"] { --fr: conic-gradient(from var(--spin), #1A1712 0 60%, #F0B33A 72%, #FFF8E1 76%, #F0B33A 80%, #1A1712 92%); animation: spin 5s linear infinite; }
@media (prefers-reduced-motion: reduce) { .avatar[data-frame] { animation: none !important; } }
/* Bursts (public/js/bursts.js) float above everything and never take clicks. */
.burst-layer { position: fixed; inset: 0; pointer-events: none; z-index: 70; overflow: hidden; }
.burst-p { position: absolute; display: block; will-change: transform, opacity; }
@property --spin { syntax: "<angle>"; inherits: true; initial-value: 0deg; }
@keyframes spin { to { --spin: 360deg; } }
/* Equipped titles read like a byline. */
.badge-title { display: inline-block; font: italic 600 .9rem/1.2 var(--display); color: var(--ink-2); }
.badge-title::before { content: "— "; }

/* ---- sparks ---- */
.sparks { font-variant-numeric: tabular-nums; white-space: nowrap; }
.sparks .g { color: var(--gold); }

/* ---- prize envelopes: rarity is the wax seal ---- */
.envelope { width: var(--es, 92px); height: auto; overflow: visible; display: block; }
.envelope .env-back { fill: var(--paper-3); stroke: var(--ink); stroke-width: 1.5; }
.envelope .env-card { fill: var(--paper-2); stroke: var(--rule); }
.envelope .env-front { fill: color-mix(in srgb, var(--paper-3) 70%, var(--paper-2)); stroke: var(--ink); stroke-width: 1.5; stroke-linejoin: round; }
.envelope .env-flap { fill: var(--paper-2); stroke: var(--ink); stroke-width: 1.5; stroke-linejoin: round; transform-origin: 60px 10px; transform-box: view-box; }
.envelope .env-seal circle { fill: var(--rc); stroke: color-mix(in srgb, var(--rc) 60%, #000); stroke-width: 1.5; }
.envelope .env-seal path { fill: color-mix(in srgb, var(--rc) 40%, #fff); }
.prize-row { display: flex; gap: var(--s3); overflow-x: auto; padding: 4px 2px 8px; scrollbar-width: none; }
.prize-slot { display: grid; justify-items: center; gap: 4px; background: transparent; border: 0; padding: var(--s2) var(--s2) var(--s3); min-width: 120px; box-shadow: none; border-radius: var(--r-1); }
.prize-slot:hover:not(:disabled) { background: var(--paper-3); }
.prize-slot .envelope { transition: transform .2s var(--ease-out); }
.prize-slot:hover .envelope { transform: rotate(-3deg) translateY(-2px); }
.prize-slot b { font: 700 .875rem var(--body); }
.prize-stage { display: flex; flex-direction: column; align-items: center; gap: var(--s4); text-align: center; min-height: 260px; justify-content: center; }
.prize-stage h2 { font: italic 700 1.4rem var(--display); }
.prize-stage .open-btn { background: none; border: 0; padding: 0; box-shadow: none; min-height: 0; }
.prize-stage .open-btn:hover { background: none; }
.prize-stage .envelope { --es: 180px; }
.prize-stage .wiggle .envelope { animation: wiggle .45s ease-in-out 2; }
@keyframes wiggle { 25% { transform: rotate(-5deg); } 75% { transform: rotate(5deg); } }
/* Opening: the flap lifts, the card slides up out of the envelope. */
.prize-stage .opening .env-flap { animation: flapOpen .35s var(--ease-out) forwards; }
.prize-stage .opening .env-seal { animation: sealPop .25s ease-in forwards; }
.prize-stage .opening .env-card { animation: cardUp .45s .25s var(--ease-out) forwards; }
@keyframes flapOpen { to { transform: scaleY(-1); } }
@keyframes sealPop { to { transform: translateY(-6px) scale(1.3); opacity: 0; } }
@keyframes cardUp { to { transform: translateY(-46px); } }
/* ---- the show (engage.js openChest) ---- */
.prize-stage .open-btn { position: relative; isolation: isolate; }
/* Idle: drops in, then floats, with a soft glow in the seal colour breathing behind it. */
.prize-stage .open-btn.idle .envelope { animation: envDrop .6s var(--ease-snap, cubic-bezier(.2, 1.4, .4, 1)) both, envFloat 2.8s .6s ease-in-out infinite; }
.env-glow { position: absolute; inset: 10% 5%; z-index: -1; border-radius: 50%; background: radial-gradient(closest-side, color-mix(in srgb, var(--rc) 55%, transparent), transparent); filter: blur(10px); opacity: .55; animation: glowBreathe 2.8s ease-in-out infinite; pointer-events: none; }
.prize-stage.rarity-common .env-glow { opacity: .25; }
@keyframes envDrop { from { transform: translateY(-60px) rotate(-8deg) scale(.7); opacity: 0; } }
@keyframes envFloat { 50% { transform: translateY(-7px) rotate(1.5deg); } }
@keyframes glowBreathe { 50% { transform: scale(1.12); opacity: .8; } }
/* Charging: the shake builds, the glow swells and the rays speed up while the server rolls the contents. */
.prize-stage .open-btn.charging .envelope { animation: charge var(--charge, .9s) cubic-bezier(.5, 0, 1, 1) both; }
.prize-stage .open-btn.charging .env-glow { animation: glowCharge var(--charge, .9s) ease-in both; }
.prize-stage:has(.charging)::before { animation-duration: 2.5s; }
@keyframes charge {
  0% { transform: none; } 10% { transform: rotate(-3deg); } 20% { transform: rotate(3deg); } 30% { transform: rotate(-5deg) scale(1.02); }
  40% { transform: rotate(5deg) scale(1.03); } 50% { transform: rotate(-7deg) scale(1.04); } 60% { transform: rotate(7deg) scale(1.05) translateX(-2px); }
  70% { transform: rotate(-9deg) scale(1.07) translateX(3px); } 80% { transform: rotate(9deg) scale(1.09) translateX(-3px); }
  90% { transform: rotate(-11deg) scale(1.12) translateX(4px); } 100% { transform: scale(1.16); }
}
@keyframes glowCharge { to { transform: scale(1.7); opacity: 1; filter: blur(16px); } }
/* The burst: a flash, wax shards, then the envelope sinks away as the card rises. */
.prize-stage .open-btn.opening .envelope { animation: envAway .8s .35s ease-in both; }
.prize-stage .open-btn.opening .env-glow { animation: glowOut .6s ease-out both; }
@keyframes envAway { to { transform: translateY(30px) scale(.85); opacity: 0; } }
@keyframes glowOut { from { transform: scale(1.7); opacity: 1; } to { transform: scale(2.6); opacity: 0; } }
.prize-flash { position: absolute; inset: -40px; z-index: 5; pointer-events: none; background: radial-gradient(circle at 50% 50%, #fff 0, color-mix(in srgb, var(--rc) 70%, #fff) 22%, transparent 60%); animation: flash .7s ease-out both; }
@keyframes flash { 0% { opacity: 0; } 12% { opacity: .95; } 100% { opacity: 0; } }
.shards { position: absolute; left: 50%; top: 50%; z-index: 6; pointer-events: none; }
.shards i { position: absolute; width: 10px; height: 7px; margin: -3px -5px; border-radius: 2px 5px 2px 4px; background: var(--rc); box-shadow: 0 0 6px color-mix(in srgb, var(--rc) 60%, transparent);
  animation: shard .75s cubic-bezier(.15, .7, .3, 1) both; }
@keyframes shard { from { transform: rotate(var(--a)) translateX(0) scale(1.2); opacity: 1; } to { transform: rotate(var(--a)) translateX(var(--d)) rotate(200deg) scale(.4); opacity: 0; } }
.prize-stage.quake { animation: quake .45s .05s ease-out; }
@keyframes quake { 20% { translate: -5px 2px; } 40% { translate: 5px -2px; } 60% { translate: -3px 1px; } 80% { translate: 2px 0; } }
/* The reveal: each find flips in on its own beat, a light sweeps across it, and a ring of its colour pulses out. */
.loot-item { animation: flipIn .7s calc(.15s + var(--i, 0) * .45s) var(--ease-snap, cubic-bezier(.2, 1.4, .4, 1)) both; overflow: hidden; }
.loot-item + .loot-item { animation-delay: calc(.15s + var(--i, 0) * .45s); }
@keyframes flipIn { 0% { transform: perspective(900px) rotateY(-95deg) scale(.8); opacity: 0; } 55% { transform: perspective(900px) rotateY(12deg) scale(1.05); opacity: 1; } 100% { transform: none; } }
.loot-item::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(105deg, transparent 35%, rgb(255 255 255 / .65) 50%, transparent 65%); translate: -120% 0;
  animation: sweep .9s calc(.6s + var(--i, 0) * .45s) ease-in-out both; }
@keyframes sweep { to { translate: 120% 0; } }
.loot-item.rarity-epic::after, .loot-item.rarity-legendary::after { animation-iteration-count: 2; }
.loot-item .show { animation: showPop .5s calc(.45s + var(--i, 0) * .45s) var(--ease-snap, cubic-bezier(.2, 1.4, .4, 1)) both; }
@keyframes showPop { from { transform: scale(.4); opacity: 0; } }
.loot > div { animation-delay: calc(.2s + var(--after, 0) * .45s); }
.loot > div:nth-child(2) { animation-delay: calc(.3s + var(--after, 0) * .45s); } .loot > div:nth-child(3) { animation-delay: calc(.4s + var(--after, 0) * .45s); }
.loot .stamp { animation-delay: calc(1.25s + var(--after, 0) * .45s); }
@media (prefers-reduced-motion: reduce) {
  .prize-stage .open-btn .envelope, .env-glow, .prize-flash, .shards i, .prize-stage.quake, .loot-item, .loot-item::after, .loot-item .show { animation: none !important; }
  .shards, .loot-item::after { display: none; }
}
.loot { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: var(--s3); width: 100%; }
.loot > div { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: var(--s3); border-top: 3px solid var(--rc, var(--ink)); background: var(--paper-3); text-align: center; animation: rise .4s var(--ease-out) both; }
.loot > div:nth-child(2) { animation-delay: .1s; } .loot > div:nth-child(3) { animation-delay: .2s; } .loot > div:nth-child(4) { animation-delay: .3s; }
.loot .big { font: 800 1.9rem/1.1 var(--display); display: inline-flex; align-items: center; gap: 6px; font-variant-numeric: tabular-nums; }
.loot .big .g { width: 26px; height: 26px; }

/* ---- quests: a numbered ladder of three ---- */
.quests { counter-reset: quest; }
.quest { display: grid; grid-template-columns: 2rem minmax(0, 1fr) auto; gap: 6px 10px; align-items: baseline; padding: var(--s3) 0; border-bottom: 1px solid var(--rule); counter-increment: quest; }
.quest:last-child { border-bottom: 0; }
.quest::before { content: counter(quest); font: 800 1.4rem/1 var(--display); color: var(--ink-3); grid-row: span 2; }
.quest b { font-weight: 600; }
.quest .qr { font: 700 .875rem var(--body); font-variant-numeric: tabular-nums; display: inline-flex; gap: 4px; align-items: center; }
.quest .qbar { grid-column: 2 / -1; height: 6px; background: var(--paper-3); overflow: hidden; border-radius: 3px; display: block; }
.quest .qbar i { display: block; height: 100%; background: var(--ink); transition: width .9s var(--ease-out); }
.quest .qn { grid-column: 2 / -1; font-size: .78rem; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.quest.done::before { content: "✓"; color: var(--right); }
.quest.done .qbar i { background: var(--right); }
.quest.done b { color: var(--ink-2); text-decoration: line-through; text-decoration-color: var(--rule); }
.quest.just { animation: rise .45s var(--ease-out); }
.quest-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); flex-wrap: wrap; padding-top: var(--s3); border-top: 1px solid var(--ink); font-size: .9rem; }

/* ---- streak at risk: the one place the programme raises its voice ---- */
.boxscore .risk b { color: var(--signal); }
.boxscore .risk span { color: var(--signal); font-weight: 600; }
.boxscore .cold b { color: var(--ink-3); }

/* ---- leagues ---- */
.league-mark { width: 1.4em; height: 1.4em; stroke-width: 1.6; color: var(--gold); }
.zone { font: 700 .72rem/1.3 var(--body); padding: 2px 6px; border-radius: var(--r-0); white-space: nowrap; }
.zone.promote { background: var(--right); color: var(--paper-2); }
.zone.demote { background: var(--signal); color: var(--on-signal); }
.zone.stay { box-shadow: inset 0 0 0 1px var(--rule); color: var(--ink-2); }
.board li.promote-line { border-bottom: 2px solid var(--right); position: relative; }
.board li.promote-line::after { content: "Promotion zone ↑"; position: absolute; right: var(--s4); bottom: -9px; font: 700 .65rem/1 var(--body); background: var(--right); color: var(--paper-2); padding: 3px 6px; }
.board li.demote-line { border-top: 2px solid var(--signal); }
.ladder { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 2px; border-top: 1px solid var(--ink); border-bottom: 1px solid var(--ink); padding: var(--s3) 0; }
.ladder span { display: flex; flex-direction: column; align-items: center; gap: 4px; font: 600 .7rem/1.1 var(--body); color: var(--ink-3); text-align: center; min-width: 0; }
.ladder span .g { width: 26px; height: 26px; color: var(--ink-3); }
.ladder span.passed .g { color: var(--ink-2); }
.ladder span.here { color: var(--ink); }
.ladder span.here .g { color: var(--gold); width: 34px; height: 34px; margin-top: -4px; }
@media (max-width: 420px) { .ladder span { font-size: 0; } .ladder span.here { font-size: .7rem; } }

/* ---- match extras ---- */
.insights { --cols: 3; }
.insights .rare { grid-column: 1 / -1; border-left: 0 !important; padding-left: 0 !important; border-top: 1px solid var(--rule); }
.insights .rare b { font: italic 600 1.05rem/1.3 var(--display); white-space: normal; }

/* ---- shop: the kiosk ---- */
.shop-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--s3); }
.item-card { display: flex; flex-direction: column; gap: var(--s2); padding: var(--s4) var(--s3) var(--s3); border-radius: var(--r-1); background: var(--paper-2); border: 1px solid var(--rule); border-top: 4px solid var(--rc, var(--ink)); position: relative; }
.item-card.featured { border-color: var(--ink); border-top-color: var(--rc, var(--ink)); }
.item-card .preview { height: 78px; display: grid; place-items: center; }
.item-card .preview .avatar { --size: 56px; }
.item-card .preview .g { width: 44px; height: 44px; stroke-width: 1.4; }
.item-card .preview .badge-title { font-size: 1.15rem; color: var(--ink); }
.item-card .preview .badge-title::before { content: ""; }
.item-card b { font: 700 1.05rem/1.15 var(--display); }
.item-card .ribbon { font: 700 .7rem/1 var(--body); letter-spacing: .04em; color: var(--rc); }
.item-card button { width: 100%; min-height: 40px; padding: 8px; margin-top: auto; }
.item-card .price { display: inline-flex; gap: 4px; align-items: center; font-variant-numeric: tabular-nums; }
.boost-on { display: inline-flex; gap: 6px; align-items: center; font: 700 .875rem var(--body); color: var(--ink); }
.boost-on .g { color: var(--gold); }

/* Shop: collectibles grouped by kind; burst demos; reaction packs. */
.kind-head { display: flex; justify-content: space-between; font: 700 .8rem var(--body); text-transform: uppercase; letter-spacing: .08em; color: var(--ink-2); margin: var(--s4) 0 var(--s2); }
.burst-demo { display: inline-flex; flex-direction: column; align-items: center; gap: 2px; background: transparent; border: 0; box-shadow: none; min-height: 64px; }
.burst-demo .g { width: 32px; height: 32px; color: var(--gold); }
.emote-row { font-size: 1.6rem; letter-spacing: .1em; }

/* ---- the envelope reveal ---- */
.prize-stage { position: relative; isolation: isolate; }
/* Light rays behind a Rare-or-better envelope, in its seal colour. */
.prize-stage.rarity-rare::before, .prize-stage.rarity-epic::before, .prize-stage.rarity-legendary::before {
  content: ""; position: absolute; left: 50%; top: 50%; width: 520px; height: 520px; translate: -50% -50%; z-index: -1; pointer-events: none;
  background: repeating-conic-gradient(from var(--spin), color-mix(in srgb, var(--rc) 22%, transparent) 0 8deg, transparent 0 22deg);
  -webkit-mask: radial-gradient(circle, #000 15%, transparent 62%); mask: radial-gradient(circle, #000 15%, transparent 62%);
  animation: spin 18s linear infinite;
}
.prize-stage.rarity-legendary::before { background: repeating-conic-gradient(from var(--spin), color-mix(in srgb, var(--r-legendary) 40%, transparent) 0 6deg, transparent 0 15deg); animation-duration: 9s; }
.loot-item { position: relative; display: grid; justify-items: center; gap: var(--s2); width: 100%; padding: calc(var(--s5, 28px) + 18px) var(--s4) var(--s4); border: 2px solid var(--rc); border-radius: var(--r-2, 12px);
  background: radial-gradient(circle at 50% 30%, color-mix(in srgb, var(--rc) 18%, var(--paper-2)), var(--paper-2) 70%); animation: lootIn .55s var(--ease-snap, cubic-bezier(.2, 1.4, .4, 1)) both; }
.loot-item + .loot-item { animation-delay: .35s; }
.loot-item .ribbon { position: absolute; top: 10px; background: var(--rc); color: var(--paper-2); font: 800 .72rem var(--body); letter-spacing: .08em; text-transform: uppercase; padding: 3px 10px; border-radius: 99px; }
.loot-item .show { min-height: 110px; display: grid; place-items: center; }
.loot-item .show .badge-title { font-size: 1.5rem; }
.loot-item b { font: 800 1.35rem var(--display); }
.loot-item.rarity-legendary { box-shadow: 0 0 0 4px color-mix(in srgb, var(--r-legendary) 25%, transparent), 0 10px 40px color-mix(in srgb, var(--r-legendary) 35%, transparent); }
@keyframes lootIn { from { opacity: 0; transform: translateY(18px) scale(.9) rotateX(40deg); } }
.loot .jackpot { position: relative; }
.stamp { position: absolute; top: -10px; right: -6px; rotate: 8deg; background: var(--signal); color: var(--on-signal, #fff); font: 900 .8rem var(--display); padding: 4px 8px; border-radius: 4px; animation: stampIn .4s .5s var(--ease-snap, ease-out) both; }
@keyframes stampIn { from { opacity: 0; transform: scale(2.2); } }
@media (prefers-reduced-motion: reduce) { .prize-stage::before { animation: none !important; } .loot-item, .stamp { animation: none; } }
