/*!
 * gift-open.css  v1.0
 * 禮物開箱動態：純 CSS 特效 + 極薄的 JS 控制（gift-open.js）
 *
 * 鐵則
 *  1. 所有動畫只動 transform / opacity（含 rotate、scale、translate 屬性），不觸發排版與重繪。
 *  2. 只用 CSS 變數 --gfx-* 調整外觀與節奏；不要改 keyframes 內的數值。
 *  3. 光芒、光環、閃光會超出舞台範圍：元件的容器請勿設 overflow:hidden。
 *     若特效超出視窗造成頁面橫向捲軸（手機常見），只在最外層頁面容器加 overflow-x:clip。
 *
 * 狀態 class（由 gift-open.js 依序加到 .gfx 根元素）：
 *   is-playing → is-shaking → is-flashing → is-open + is-pop + is-burst
 *   is-paused（離開畫面／分頁隱藏時暫停無限動畫）
 */

/* ───────── 1. Token（可調參數）───────── */
:root{
  --gfx-coin-symbol:"$";       /* 金幣幣面的符號（字串，需含引號）。例："¥"、"€"。可設在 :root 或任一祖先 */
  --gfx-spinner-rgb:42,29,0;   /* 按鈕轉圈的顏色 RGB（預設是金色按鈕上的深色字）*/
  --gfx-speed:1;               /* 時間倍率：1 正常、2 慢 2 倍、0.5 快 2 倍。
                                  請設在 :root 或元件與「獎勵數字」的共同祖先，兩邊才會一起變慢 */
}
.gfx{
  --gfx-w:323px;               /* 舞台寬 */
  --gfx-h:220px;               /* 舞台高 */
  --gfx-box:170px;             /* 盒子邊長 */
  --gfx-halo:240px;            /* 常駐光暈直徑 */
  --gfx-rays:380px;            /* 光芒直徑；實際可見半徑約為直徑的 0.34 倍（≈130px） */
  --gfx-spin:16s;              /* 光芒轉一圈的時間（開箱後 1.2 秒才開始轉） */
  --gfx-gold:255,238,175;      /* 主光色 RGB（逗號分隔，供 rgba() 使用） */
  --gfx-gold-hi:255,246,205;   /* 亮部光色 RGB（開箱瞬間的亮閃） */
  --gfx-mote-scale:.743;       /* 浮光點整體範圍縮放 */

  position:relative;
  width:var(--gfx-w);
  height:var(--gfx-h);
  isolation:isolate;           /* 特效的 z-index 只在元件內部排序，不會蓋到外面的文字 */
}

/* ───────── 2. 共同定位（全部以舞台正中心為原點）───────── */
.gfx__halo,.gfx__ring,.gfx__rays,.gfx__flash,.gfx__box,
.gfx__coin,.gfx__spark,.gfx__motes{position:absolute;left:50%;top:50%;pointer-events:none}
.gfx__glow{position:absolute;inset:0;pointer-events:none}

/* ───────── 3. 盒子與兩張圖（硬切換，由閃光遮住）───────── */
.gfx__box{
  z-index:3;
  width:var(--gfx-box);height:var(--gfx-box);
  margin:calc(var(--gfx-box)/-2) 0 0 calc(var(--gfx-box)/-2);
}
.gfx__img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain}
.gfx__img--open{opacity:0}
.gfx.is-open .gfx__img--closed{opacity:0}
.gfx.is-open .gfx__img--open{opacity:1}

/* 0–700ms 抖動（逐步放大到 1.08）→ 開箱瞬間彈跳 */
.gfx.is-shaking .gfx__box{animation:gfx-shake calc(.7s*var(--gfx-speed)) ease-in-out}
.gfx.is-pop .gfx__box{animation:gfx-pop calc(.55s*var(--gfx-speed)) cubic-bezier(.2,1.6,.4,1)}
@keyframes gfx-shake{
  0%,100%{transform:rotate(0) scale(1)}
  15%{transform:rotate(-6deg) scale(1.02)}
  30%{transform:rotate(6deg) scale(1.03)}
  45%{transform:rotate(-5deg) scale(1.04)}
  60%{transform:rotate(5deg) scale(1.05)}
  80%{transform:rotate(-2deg) scale(1.08)}
}
@keyframes gfx-pop{0%{transform:scale(.86)}100%{transform:scale(1)}}

/* ───────── 4. 常駐光暈 ───────── */
.gfx__halo{
  z-index:1;
  width:var(--gfx-halo);height:var(--gfx-halo);
  margin:calc(var(--gfx-halo)/-2) 0 0 calc(var(--gfx-halo)/-2);
  border-radius:50%;
  background:radial-gradient(circle,rgba(239,222,171,.28) 0%,rgba(239,222,171,0) 65%);
  transition:transform .4s,opacity .4s;
}
.gfx.is-shaking .gfx__halo{transform:scale(1.25);opacity:1}          /* 抖動時蓄力放大 */
.gfx.is-open .gfx__halo{                                              /* 開箱後更亮，停在 1.3 倍 .8 透明 */
  background:radial-gradient(circle,rgba(var(--gfx-gold),.45) 0%,rgba(239,222,171,0) 68%);
  animation:gfx-halo-beat calc(1.2s*var(--gfx-speed)) ease-out forwards;
}
@keyframes gfx-halo-beat{
  0%{transform:scale(1.42);opacity:1}
  100%{transform:scale(1.3);opacity:.8}
}

/* ───────── 5. 閃光（蓋住換圖那一瞬間）───────── */
.gfx__flash{
  z-index:6;
  width:420px;height:420px;margin:-210px 0 0 -210px;
  border-radius:50%;opacity:0;
  background:radial-gradient(circle,#fff 0%,#fff6d6 22%,rgba(255,230,160,.85) 38%,rgba(255,220,140,0) 66%);
}
.gfx.is-flashing .gfx__flash{animation:gfx-flash calc(.62s*var(--gfx-speed)) ease-out forwards}
@keyframes gfx-flash{
  0%{opacity:0;transform:scale(.3)}
  30%{opacity:1;transform:scale(1)}      /* 約 190ms 最亮 → 此刻換圖 */
  100%{opacity:0;transform:scale(1.25)}
}

/* ───────── 6. 光環（開箱時只播一次）───────── */
.gfx__ring{
  z-index:2;
  width:440px;height:440px;margin:-220px 0 0 -220px;
  border-radius:50%;opacity:0;
  mix-blend-mode:screen;                 /* 疊在光芒上時，交會處自然變亮 */
  background:radial-gradient(circle,
    rgba(var(--gfx-gold),0) 34%,rgba(255,240,190,.55) 43%,rgba(var(--gfx-gold),.18) 50%,rgba(var(--gfx-gold),0) 58%);
}
.gfx.is-open .gfx__ring{animation:gfx-ring-once calc(1.1s*var(--gfx-speed)) cubic-bezier(.15,.7,.3,1) forwards}
@keyframes gfx-ring-once{
  0%{transform:scale(.45);opacity:1}
  100%{transform:scale(1.6);opacity:0}
}

/* ───────── 7. 光芒：8 道、柔邊、單層；爆開減速後慢轉 ───────── */
.gfx__rays{
  z-index:2;
  width:var(--gfx-rays);height:var(--gfx-rays);
  margin:calc(var(--gfx-rays)/-2) 0 0 calc(var(--gfx-rays)/-2);
  border-radius:50%;opacity:0;
  background:repeating-conic-gradient(from 0deg,
    rgba(var(--gfx-gold),0) 0deg,rgba(var(--gfx-gold),.6) 10deg,rgba(var(--gfx-gold),0) 20deg,rgba(var(--gfx-gold),0) 45deg);
  -webkit-mask:radial-gradient(circle,#000 14%,rgba(0,0,0,.75) 40%,transparent 68%);
          mask:radial-gradient(circle,#000 14%,rgba(0,0,0,.75) 40%,transparent 68%);
}
.gfx.is-open .gfx__rays{
  animation:
    gfx-rays-burst calc(1.2s*var(--gfx-speed)) cubic-bezier(.1,.8,.3,1) forwards,
    gfx-spin calc(var(--gfx-spin)*var(--gfx-speed)) linear calc(1.2s*var(--gfx-speed)) infinite;
}
@keyframes gfx-rays-burst{
  0%{opacity:0;transform:scale(.35) rotate(-60deg)}
  35%{opacity:1}
  100%{opacity:1;transform:scale(1) rotate(0deg)}
}
@keyframes gfx-spin{to{rotate:360deg}}     /* 用 rotate 屬性，與 burst 的 transform 互不干擾 */

/* 亮部：與光芒同位置、同爆開，外層 .gfx__glow 只做「亮一下就退」的透明度脈動 */
.gfx__glow{z-index:2;opacity:0}
.gfx__rays--bright{
  opacity:1;
  background:repeating-conic-gradient(from 0deg,
    rgba(var(--gfx-gold-hi),0) 0deg,rgba(var(--gfx-gold-hi),.75) 10deg,rgba(var(--gfx-gold-hi),0) 20deg,rgba(var(--gfx-gold-hi),0) 45deg);
}
.gfx.is-open .gfx__glow{animation:gfx-glow-pulse calc(1.2s*var(--gfx-speed)) ease-out both}
.gfx.is-open .gfx__rays--bright{
  animation:
    gfx-rays-burst-flat calc(1.2s*var(--gfx-speed)) cubic-bezier(.1,.8,.3,1) forwards,
    gfx-spin calc(var(--gfx-spin)*var(--gfx-speed)) linear calc(1.2s*var(--gfx-speed)) infinite;
}
@keyframes gfx-glow-pulse{0%{opacity:.7}35%{opacity:0}100%{opacity:0}}
@keyframes gfx-rays-burst-flat{
  0%{transform:scale(.35) rotate(-60deg)}
  100%{transform:scale(1) rotate(0deg)}
}

/* ───────── 8. 金幣與星星（全部 CSS 繪製，位置由 JS 以變數帶入）─────────
   金幣幣面是錢幣符號（--gfx-coin-symbol）；.gfx__spark 是飄散的四角閃光點，與幣面無關 */
.gfx__coin{
  z-index:5;
  width:26px;height:26px;margin:-13px;border-radius:50%;opacity:0;
  background:radial-gradient(circle at 35% 30%,#fff3cf 0 18%,#f3cf6f 45%,#b8862f 100%);
  box-shadow:inset 0 0 0 3px rgba(176,127,42,.55),0 0 8px rgba(255,214,120,.6);
}
.gfx__coin::after{                      /* 幣面上的錢幣符號（文字，會跟著金幣一起縮放、旋轉）*/
  content:var(--gfx-coin-symbol);
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font:800 16px/1 ui-rounded,"SF Pro Rounded",system-ui,-apple-system,"Segoe UI","Helvetica Neue",Arial,sans-serif;
  color:#a8741f;
  text-shadow:0 1px 0 rgba(255,243,207,.75);   /* 浮雕感：下緣一道亮邊 */
}
.gfx.is-burst .gfx__coin{
  animation:gfx-coin calc(var(--d)*var(--gfx-speed)) cubic-bezier(.15,.7,.3,1) calc(var(--delay)*var(--gfx-speed)) forwards;
}
@keyframes gfx-coin{                     /* --x --y --r --s --d --delay 由 JS 逐顆指定 */
  0%{opacity:0;transform:translate(0,0) scale(.4) rotate(0)}
  10%{opacity:1}
  70%{opacity:1;transform:translate(var(--x),var(--y)) scale(var(--s)) rotate(var(--r))}
  100%{opacity:0;transform:translate(var(--x),calc(var(--y) + 60px)) scale(var(--s)) rotate(var(--r))}
}
.gfx__spark{
  z-index:5;
  width:14px;height:14px;margin:-7px;opacity:0;background:#fff8e1;
  clip-path:polygon(50% 0,62% 38%,100% 50%,62% 62%,50% 100%,38% 62%,0 50%,38% 38%);
}
.gfx.is-burst .gfx__spark{animation:gfx-spark calc(.9s*var(--gfx-speed)) ease-out calc(var(--delay)*var(--gfx-speed)) forwards}
@keyframes gfx-spark{
  0%{opacity:0;transform:translate(var(--x),var(--y)) scale(.2)}
  40%{opacity:1;transform:translate(var(--x),var(--y)) scale(1.2)}
  100%{opacity:0;transform:translate(var(--x),var(--y)) scale(.4)}
}

/* ───────── 9. 浮光點 4 顆（開箱後淡入，持續循環）─────────
   三層各用不同週期（互不整除）：上飄／左右飄移／忽明忽暗，所以看起來不會同步 */
.gfx__motes{
  z-index:7;width:0;height:0;
  transform:scale(var(--gfx-mote-scale));
  opacity:0;transition:opacity .4s;
}
.gfx.is-open .gfx__motes{opacity:1}
.gfx__mote,.gfx__mote-sway{position:absolute;left:0;top:0;width:0;height:0}
.gfx__mote-dot{
  position:absolute;width:var(--d);height:var(--d);margin:calc(var(--d)/-2);border-radius:50%;
  background:radial-gradient(circle,#fffbea 0%,#fff1c4 30%,rgba(255,236,170,.5) 52%,rgba(255,236,170,0) 74%);
}
@keyframes gfx-mote-rise{                /* --x --y0 --y1 */
  0%{transform:translate(var(--x),var(--y0));opacity:0}
  18%{opacity:1}
  80%{opacity:.8}
  100%{transform:translate(var(--x),var(--y1));opacity:0}
}
@keyframes gfx-mote-sway{0%,100%{translate:calc(var(--a)*-1) 0}50%{translate:var(--a) 0}}   /* --a */
@keyframes gfx-mote-twinkle{0%,100%{opacity:.35}50%{opacity:1}}
.gfx__motes *{animation-play-state:paused}                    /* 開箱前不跑 */
.gfx.is-open .gfx__motes *{animation-play-state:running}

/* ───────── 10. 獎勵數字（選用；放在 .gfx 之後的兄弟節點）───────── */
.gfx-reward{opacity:0;transform:translateY(10px)}
.gfx.is-open ~ .gfx-reward{animation:gfx-rise calc(.5s*var(--gfx-speed)) ease-out calc(.25s*var(--gfx-speed)) forwards}
@keyframes gfx-rise{to{opacity:1;transform:none}}

/* ───────── 11. 效能與無障礙 ───────── */
/* 播放期間才提示 GPU，播完由 JS 移除 */
.gfx.is-playing .gfx__box,.gfx.is-playing .gfx__rays,.gfx.is-playing .gfx__glow,
.gfx.is-playing .gfx__flash,.gfx.is-playing .gfx__ring,
.gfx.is-playing .gfx__coin,.gfx.is-playing .gfx__spark{will-change:transform,opacity}
/* 離開畫面或分頁隱藏 → 暫停所有動畫（JS 切換此 class） */
.gfx.is-paused,.gfx.is-paused *{animation-play-state:paused!important}
/* 系統開了「減少動態效果」：不抖、不噴、不旋轉，只淡入 */
@keyframes gfx-fade-in{from{opacity:0}to{opacity:1}}
@media (prefers-reduced-motion:reduce){
  .gfx__ring,.gfx__glow,.gfx__flash,.gfx__coin,.gfx__spark,.gfx__motes{display:none}
  .gfx.is-shaking .gfx__box{animation:none}
  .gfx.is-open .gfx__rays{animation:gfx-fade-in .3s ease-out forwards}
}

/* ───────── 12. 按鈕內的轉圈（選用）─────────
   點擊後把按鈕設為 disabled，並把按鈕內容換成 <span class="gfx-spinner" aria-hidden="true"></span>。
   轉圈不受 --gfx-speed 影響（慢動作除錯時也維持正常轉速）。 */
.gfx-spinner{
  display:inline-block;width:18px;height:18px;vertical-align:middle;
  border-radius:50%;
  border:2px solid rgba(var(--gfx-spinner-rgb),.25);
  border-top-color:rgb(var(--gfx-spinner-rgb));
  animation:gfx-spinner .8s linear infinite;
}
@keyframes gfx-spinner{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.gfx-spinner{animation-duration:1.6s}}   /* 載入提示不可拿掉，只放慢 */
