/* ============================================================
   BLING — viên đá trên váy cô dâu "mời chạm".
   Váy vốn đã lấp lánh sẵn, nên viên đá phải khác hạt cườm ở thứ mắt người
   đọc ra ngay: NHỊP ĐỀU. Tia sao 4 cánh nở rồi xoay theo nhịp đều 1.8s,
   hạt cườm thật thì nhấp nháy loạn — cái đều đặn đó đọc ra là bấm được.

   Chạm: tia sáng bắn từ CHÍNH hạt đó xuống dòng ký tên ở đáy màn; lời chúc
   của khách nổi lên THẾ CHỖ lời chúc đang hiện. Hai nhịp chồng lên nhau —
   chữ đã nổi được nửa đường thì tia mới chạm tới, không chờ nhau.
   ============================================================ */
/* Lớp đá dịch y hệt ảnh bên trong iframe: app-stage.trackCam ghi thẳng `transform`
   (translate + scale) lên chính lớp này mỗi khung — không qua biến CSS, WebKit rò bộ nhớ
   theo từng lần đổi biến (xem trackCam). Đá to nhỏ theo ảnh luôn, vì viên đá vốn là hạt
   cườm trên váy. */
.bl-layer{position:absolute;inset:0;z-index:6;pointer-events:none;
  transform-origin:50% 50%;
  will-change:transform}

/* ---- viên đá: không vẽ hình gì, chỉ cộng sáng lên hạt sequin engine đang chiếu ----
   12 tia xếp ba tầng lệch nhau 22.5°: tầng ngang-dọc dài nhất, tầng chéo 45° ngắn hơn,
   tầng 22.5° ngắn nhất và mờ nhất. Ba tầng nở/xoay lệch pha nên lúc nào cũng có tia
   đang vươn ra — đứng yên một khung hình vẫn thấy ngôi sao, không phải chấm sáng. */
.bl{position:absolute;left:var(--x);top:var(--y);width:var(--sz,17cqw);height:var(--sz,17cqw);
  transform:translate(-50%,-50%);pointer-events:auto;cursor:pointer;
  background:none;border:0;padding:0;appearance:none;-webkit-appearance:none;display:block;
  animation:bl-in .55s cubic-bezier(.2,1.2,.4,1) both}
.bl::before{content:'';position:absolute;left:50%;top:50%;   /* vùng chạm tối thiểu 52px */
  width:max(52px,110%);height:max(52px,110%);transform:translate(-50%,-50%)}
.bl>i{position:absolute;display:block;pointer-events:none;mix-blend-mode:screen}
.bl.big{--sz:23cqw}
.bl.gone{pointer-events:none;animation:bl-out .5s ease-out forwards}
.bl.fired{pointer-events:none;animation:bl-fire .55s cubic-bezier(.3,0,.4,1) forwards}

/* lõi: điểm nóng gắt, kèm nhịp loé mạnh mỗi ~4.6s cho mắt bắt được từ xa */
.bl .core{inset:0;border-radius:50%;
  background:radial-gradient(circle,rgba(255,255,253,1) 0%,rgba(255,253,244,1) 8%,
    rgba(255,246,214,.6) 18%,rgba(255,230,158,.24) 34%,rgba(255,214,120,0) 62%);
  animation:bl-beat var(--tw,1.8s) ease-in-out infinite,
            bl-flash 4.6s ease-in-out var(--pd,0s) infinite}
/* tầng 1 · ngang + dọc, dài nhất */
.bl .flare{inset:-68%;
  background:
    linear-gradient(to right,transparent,rgba(255,252,240,.95) 50%,transparent) center/100% 1.6px no-repeat,
    linear-gradient(to bottom,transparent,rgba(255,252,240,.95) 50%,transparent) center/1.6px 100% no-repeat;
  animation:bl-flare var(--tw,1.8s) ease-in-out infinite,
            bl-flash 4.6s ease-in-out var(--pd,0s) infinite}
/* tầng 2 · chéo 45° */
.bl .flare2{inset:-44%;
  background:
    linear-gradient(to right,transparent,rgba(255,248,222,.7) 50%,transparent) center/100% 1.2px no-repeat,
    linear-gradient(to bottom,transparent,rgba(255,248,222,.7) 50%,transparent) center/1.2px 100% no-repeat;
  animation:bl-flare2 var(--tw,1.8s) ease-in-out infinite}
/* tầng 3 · lệch 22.5°, chỉ để dày tia, giữ mờ kẻo thành ngôi sao đồ hoạ */
.bl .flare3{inset:-30%;
  background:
    linear-gradient(to right,transparent,rgba(255,244,206,.42) 50%,transparent) center/100% 1px no-repeat,
    linear-gradient(to bottom,transparent,rgba(255,244,206,.42) 50%,transparent) center/1px 100% no-repeat;
  animation:bl-flare3 calc(var(--tw,1.8s) * 1.35) ease-in-out infinite}
/* vòng lan chậm — ngôn ngữ "chỗ này bấm được", nhưng mảnh để không thành nút bấm */
.bl .ring{inset:-14%;border-radius:50%;opacity:0;border:1px solid rgba(255,248,222,.85);
  animation:bl-ping 2.4s cubic-bezier(.2,.7,.3,1) var(--pd,0s) infinite}

@keyframes bl-in{from{opacity:0;transform:translate(-50%,-50%) scale(.25)}to{opacity:1;transform:translate(-50%,-50%) scale(1)}}
@keyframes bl-out{to{opacity:0;transform:translate(-50%,-50%) scale(1.9)}}
@keyframes bl-fire{0%{transform:translate(-50%,-50%) scale(1)}
  26%{transform:translate(-50%,-50%) scale(2.1);opacity:1}
  100%{transform:translate(-50%,-50%) scale(.2);opacity:0}}
/* nhịp ĐỀU — hạt cườm thật nhấp nháy ngẫu nhiên, cái đều đặn này mới đọc ra là bấm được */
/* SÀN của nhịp phải còn đủ sáng: nhịp cũ tụt xuống .5 nên nửa thời gian viên đá
   gần như biến mất, khách nhìn lướt là bỏ sót. Giờ chỉ phập phồng, không tắt. */
@keyframes bl-beat{0%,100%{opacity:.82;transform:scale(.88)}50%{opacity:1;transform:scale(1.18)}}
@keyframes bl-flare{0%,100%{transform:scale(.7) rotate(0);opacity:.66}50%{transform:scale(1.18) rotate(45deg);opacity:1}}
@keyframes bl-flare2{0%,100%{transform:scale(.58) rotate(45deg);opacity:.45}50%{transform:scale(1.04) rotate(0);opacity:.9}}
@keyframes bl-flare3{0%,100%{transform:scale(.56) rotate(22.5deg);opacity:.3}50%{transform:scale(1) rotate(67.5deg);opacity:.75}}
/* loé mạnh một nhịp: mắt bắt được viên đá kể cả khi đang nhìn chỗ khác */
@keyframes bl-flash{0%,70%,100%{filter:brightness(1)}
  78%{filter:brightness(2.3) saturate(1.15)}
  86%{filter:brightness(1.25)}}
@keyframes bl-ping{0%{opacity:.8;transform:scale(.26)}62%,100%{opacity:0;transform:scale(1.8)}}

/* nhãn nhắc ở thanh trên */
.bl-hint{position:absolute;left:0;right:0;top:0;z-index:7;pointer-events:none;text-align:center;
  padding:max(14px,calc(env(safe-area-inset-top) + 8px)) 16px 24px;
  font:500 9.5px/1.5 'Be Vietnam Pro',system-ui,sans-serif;letter-spacing:.22em;text-transform:uppercase;
  /* bỏ dải tối phủ đỉnh màn; chữ tự đứng được nhờ hai lớp bóng, một sát một toả */
  color:rgba(243,222,163,.92);text-shadow:0 1px 2px rgba(0,0,0,.95),0 2px 12px rgba(0,0,0,.85);
  opacity:0;transition:opacity .45s}
.bl-hint.on{opacity:1}

/* ============ chạm rồi: tia sáng bắn xuống dòng ký tên ============ */
.bl-comet{position:absolute;left:var(--x);top:var(--y);width:var(--sz,7cqw);height:var(--sz,7cqw);z-index:9;
  transform:translate(-50%,-50%);pointer-events:none;mix-blend-mode:screen;
  animation:bl-comet var(--fly,.9s) cubic-bezier(.5,0,.5,1) forwards}
.bl-comet i{position:absolute;inset:0;border-radius:50%;
  background:radial-gradient(circle,#fff 0%,rgba(255,246,214,.7) 28%,rgba(255,228,150,.2) 52%,transparent 74%)}
.bl-comet::after{content:'';position:absolute;left:50%;top:50%;width:2.2px;height:var(--tail,14cqh);
  transform:translate(-50%,-100%) rotate(var(--ang,180deg));transform-origin:50% 100%;
  background:linear-gradient(to top,rgba(255,252,238,.95),rgba(255,240,196,.45) 42%,transparent);
  filter:drop-shadow(0 0 3px rgba(255,240,196,.8));
  /* vệt mọc dần theo quãng đã bay — để nguyên chiều dài thì đuôi thò ngược lên trên viên đá,
     nhìn ra thành sao băng từ ngoài khung rơi vào, mất đúng ý "bắn TỪ hạt này" */
  animation:bl-tail var(--fly,.9s) cubic-bezier(.5,0,.5,1) forwards}
@keyframes bl-tail{0%{height:0}46%,100%{height:var(--tail,14cqh)}}
/* giữ sáng gần trọn đường bay rồi mới tắt — tắt sớm là tia biến mất giữa chừng */
@keyframes bl-comet{
  0%{transform:translate(-50%,-50%) scale(1.7);opacity:0}
  9%,84%{opacity:1}
  100%{transform:translate(calc(-50% + var(--dx)),calc(-50% + var(--dy))) scale(.5);opacity:0}}

/* ============ MAIN PLACE — lời chúc của khách thế chỗ ============
   Ba nhịp CHỒNG lên nhau, không xếp hàng chờ nhau:
     0%   chữ cũ chìm xuống (.28s)
     50%  tia còn đang bay thì câu chúc mới đã bắt đầu trôi xuống, mờ rồi rõ dần
     100% tia chạm: dòng ký tên mới được "viết" ra, lằn sáng quét ngang cả khối */
.mywish .mw-in{position:relative}
/* Kiểu 01 giờ có tấm mờ backdrop-filter nằm ở .mw-in::before, nên KHÔNG được đặt
   opacity hay filter lên chính .mw-in nữa: tổ tiên có opacity/filter là
   backdrop-filter mất chỗ lấy nền, tấm biến mất ngay nhịp đầu lúc chữ chìm.
   Tách ra: chữ và dòng ký tên chìm riêng, tấm mờ tự mờ bằng opacity của nó. */
.mywish.out .mw-msg,.mywish.out .mw-who{animation:mw-out .28s ease-in forwards}
.mywish.out .mw-in::before{animation:mw-outplate .28s ease-in forwards}
.mywish.in .mw-msg{animation:mw-rise .74s cubic-bezier(.2,1,.3,1) both}
@keyframes mw-out{to{opacity:0;transform:translateY(2.4cqw);filter:blur(3px)}}
@keyframes mw-outplate{to{opacity:0}}
@keyframes mw-rise{from{opacity:0;transform:translateY(-2.2cqw);filter:blur(4px)}
  to{opacity:1;transform:none;filter:none}}

/* ảnh khách đổi cùng nhịp chữ (hook `photo` của JolipoliBling). Chỉ ảnh đã tải (.ld)
   mới chạy nhịp; ảnh về trễ thì tự mờ dần vào bằng transition của .mw-photo. */
.mywish.out .mw-photo.ld{animation:mw-out .28s ease-in forwards}
.mywish.in .mw-photo.ld{animation:mw-photo-in .45s cubic-bezier(.2,1,.3,1) both}
@keyframes mw-photo-in{from{opacity:0;transform:scale(.92)}to{opacity:1;transform:none}}

/* dòng ký tên nín thở chờ tia chạm tới */
.mywish.armed .mw-who{opacity:0}

/* Lằn quét phải chạy bằng TRANSFORM của thẻ con, đừng đụng tới background-position.
   Bản cũ quét bằng background-position trên nền background-size:280%. Safari không
   nhúc nhích cái nền đó: nó vẽ nguyên dải sáng ĐỨNG IM suốt 1.1s node còn sống. Nằm
   trên ảnh thì mờ nên khó thấy, nhưng đè lên dải đen hai bên khung 9:16 là lộ ra
   thành một mảng chữ nhật sáng ngay cạnh khối chữ — nhìn ra y như lời chúc hiện
   thêm lần thứ hai rồi tắt.
   Nay dải sáng là thẻ con trượt trong khung overflow:hidden; lúc nghỉ nó nằm hẳn
   ngoài khung nên không còn gì đứng lại. Cả lằn quét lẫn đốm loé cũng dựng sẵn một
   lần rồi bật/tắt bằng class .on, khỏi tạo/xoá node giữa lúc câu chúc đang chạy.
   Bỏ mix-blend-mode: nền chỗ này vốn tối, phủ thẳng vẫn ra đúng vệt sáng đó. */
.mw-sweep{position:absolute;pointer-events:none;overflow:hidden;
  /* trùm đúng bằng tấm mờ sau chữ — ba biến dùng chung, khai ở app-wish.css */
  inset:calc(var(--mw-pt,3cqw) * -1) calc(var(--mw-px,4cqw) * -1) calc(var(--mw-pb,3cqw) * -1);
  /* mép tan y như tấm, không thì vệt sáng cắt vuông trong khi tấm thì tan mềm */
  -webkit-mask:var(--mw-mask);mask:var(--mw-mask)}
.mw-sweep i{position:absolute;left:0;top:0;bottom:0;width:58%;
  background:linear-gradient(100deg,transparent,rgba(255,248,222,.42) 50%,transparent);
  transform:translateX(-110%)}
.mw-sweep.on i{animation:mw-sweep 1s ease-out forwards}
@keyframes mw-sweep{from{transform:translateX(-110%)}to{transform:translateX(180%)}}

/* tia chạm xuống: gạch kéo ra, tên loé trắng rồi dịu về vàng */
.mywish .mw-who{position:relative}
.mywish .mw-who .ln{transform-origin:left center}
.mw-who.hit .ln{animation:mw-ln .5s cubic-bezier(.2,1,.3,1) both}
.mw-who.hit b{animation:mw-nm .85s ease-out both}
@keyframes mw-ln{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@keyframes mw-nm{
  0%{opacity:0;color:#fff;letter-spacing:.46em;text-shadow:0 0 2.6cqw rgba(255,248,222,1)}
  34%{opacity:1;color:#fff;text-shadow:0 0 2.2cqw rgba(255,248,222,.95)}
  100%{opacity:1;color:var(--gold2,#f3dea3);letter-spacing:.24em;text-shadow:none}}
.mw-spark{position:absolute;left:0;top:50%;width:15cqw;height:15cqw;margin:-7.5cqw 0 0 -5cqw;
  pointer-events:none;border-radius:50%;opacity:0;
  background:radial-gradient(circle,rgba(255,255,253,.95) 0%,rgba(255,248,222,.5) 18%,
    rgba(255,232,164,.16) 38%,transparent 64%)}
.mw-spark.on{animation:mw-spark .65s ease-out forwards}
@keyframes mw-spark{0%{opacity:0;transform:scale(.18)}16%{opacity:1;transform:scale(1)}
  100%{opacity:0;transform:scale(2.2)}}

/* Vạch đếm ngược lúc trả lời chúc về cho chủ máy. Nằm ĐÚNG trên mép tấm mờ sau
   chữ: đọc chung ba biến --mw-pt/--mw-px/--mw-pb với tấm và lằn quét (khai ở
   app-wish.css). Bản cũ để left/right:0 nên vạch cụt hơn tấm --mw-px mỗi bên
   (4cqw ở màn sân khấu), còn bottom cứng -3cqw thì lơ lửng trên mép đáy tấm — nhìn
   ra hai đường mép lệch nhau ngay dưới dòng ký tên. */
.mw-bar{position:absolute;height:1px;background:rgba(243,222,163,.16);
  left:calc(var(--mw-px,4cqw) * -1);right:calc(var(--mw-px,4cqw) * -1);
  bottom:calc(var(--mw-pb,3cqw) * -1);
  opacity:0;transition:opacity .3s}
.mywish.guest .mw-bar{opacity:1}
/* Đuôi vạch vuốt nhọn, đừng để cụt vuông: nền sáng dần nhạt về cuối, rồi thêm
   một lớp mặt nạ tan hẳn về 0 ở 16% cuối. Mặt nạ đi theo transform nên lúc vạch
   rút ngắn, đuôi vẫn nhọn đúng tỉ lệ đó. Mũi nhọn tan vào vạch nền mờ .16 chạy
   suốt bề ngang, nhìn ra một nét vót chứ không phải đoạn thẳng bị cắt.
   Vót ngắn thôi: kéo dài tới 22% cuối thì cả thân vạch nhạt theo, nhìn yếu hẳn. */
.mw-bar i{display:block;height:100%;transform-origin:left;
  background:linear-gradient(90deg,rgba(243,222,163,.92),rgba(243,222,163,.62) 70%,rgba(243,222,163,.3));
  -webkit-mask:linear-gradient(90deg,#000 84%,rgba(0,0,0,.5) 94%,transparent 100%);
  mask:linear-gradient(90deg,#000 84%,rgba(0,0,0,.5) 94%,transparent 100%)}
.mw-bar i.run{animation:mw-bar var(--hold,8s) linear forwards}
@keyframes mw-bar{from{transform:scaleX(1)}to{transform:scaleX(0)}}
