/* ===========================================================================
   Mirinda Freeze Game — layout bám 1:1 file thiết kế
   "FA_MRD VIS_ Game Freeze .ai" (4 artboard 90x160mm).

   Nguyên tắc:
   - Mọi phần tử nằm trong khung thiết kế cố định 1080x1920 (#stage), rồi
     scale-to-fit vào màn hình thật. 1 đơn vị CSS ở đây = 1 px thiết kế.
   - Phần tử KV đặt bằng 4 biến --x/--y/--w/--h khai báo ngay trong HTML,
     lấy nguyên từ bounding box của asset đã xuất từ Illustrator.
   - CSS chỉ lo trạng thái + chuyển động; không tự bịa toạ độ.
   =========================================================================== */

/* Mirinda Burst — bộ chữ tiêu đề chính thức của thương hiệu, đúng cái dùng cho
   dòng "DIỆN MẠO MỚI" trên các file KV.

   Dùng cho mọi chữ app tự vẽ trên màn chơi: nhãn "Vòng n/3" và các thông báo
   lớn giữa màn (TRƯỢT RỒI, TUYỆT ĐỈNH...). Những chữ này nằm cạnh chữ đã vẽ
   sẵn trong ảnh nền nên phải cùng một bộ chữ mới không lộ.

   Nhúng thẳng file .ttf vào đây chứ không gọi font từ đâu về: máy booth chạy
   offline hoàn toàn, và font phải có mặt ngay từ khung hình đầu. */
@font-face {
  font-family: 'Mirinda Burst';
  font-style: normal;
  font-weight: 400 900;
  font-display: block;
  src: url('../fonts/mirinda-burst.ttf') format('truetype');
}

:root {
  --c-red:      #D33626;
  --c-deep:     #B8202B;
  --c-deepdk:   #8E1620;
  --c-cyan:     #BAF4ED;
  --c-teal:     #04AA9A;
  --c-yellow:   #FCF704;
  --c-yellowdk: #EBC10E;
  --font-display: "Arial Black", "Segoe UI Black", Impact, "Arial Bold", sans-serif;
  /* Chữ app tự vẽ trên màn chơi — xem chú thích @font-face ở đầu file. */
  --font-round: 'Mirinda Burst', var(--font-display);
  --font-ui: "Segoe UI", "Helvetica Neue", Arial, system-ui, sans-serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  height: 100%;
  background: var(--c-deepdk);
  overflow: hidden;
  -webkit-user-select: none; user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  cursor: none;
}
body.show-cursor, body.show-cursor * { cursor: auto; }

img { display: block; -webkit-user-drag: none; user-drag: none; }

/* ------------------------------------------------------ khung thiết kế */
#viewport { position: fixed; inset: 0; }

#stage {
  position: absolute;
  left: 50%; top: 50%;
  width: 1080px; height: 1920px;
  transform-origin: 50% 50%;
  transform: translate(-50%, -50%);
  overflow: hidden;
  background: var(--c-red);
}

/* Phần tử KV: toạ độ tuyệt đối lấy thẳng từ artboard */
.kv {
  position: absolute;
  left:   calc(var(--x) * 1px);
  top:    calc(var(--y) * 1px);
  width:  calc(var(--w) * 1px);
  height: calc(var(--h) * 1px);
  pointer-events: none;
}

/* Nút bấm: vùng chạm đúng bằng bounding box của nút trong thiết kế */
.kvbtn {
  position: absolute;
  left:   calc(var(--x) * 1px);
  top:    calc(var(--y) * 1px);
  width:  calc(var(--w) * 1px);
  height: calc(var(--h) * 1px);
  padding: 0; border: 0; background: none;
  cursor: inherit;
  animation: btn-breathe 2.4s ease-in-out infinite;
}
.kvbtn > img { width: 100%; height: 100%; pointer-events: none; }
.kvbtn:active { transform: scale(.955); animation: none; }

@keyframes btn-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.028); }
}

/* --------------------------------------------------------------- scene */
.scene {
  position: absolute; inset: 0;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .28s ease;
}
.scene.is-active { opacity: 1; visibility: visible; pointer-events: auto; }

/* Lon ở màn chờ nhấp nhô nhẹ cho đỡ tĩnh */
.kv-float { animation: float-y 4.6s ease-in-out infinite; }
@keyframes float-y {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-14px); }
}

/* 3 dòng thể lệ / 3 khối màn thắng trượt vào lần lượt */
.scene.is-active .step,
.scene.is-active .pop {
  animation: slide-in .5s cubic-bezier(.2, .9, .25, 1.06) backwards;
  animation-delay: calc(var(--i) * .12s + .1s);
}
@keyframes slide-in {
  from { opacity: 0; transform: translateY(26px) scale(.96); }
  to   { opacity: 1; transform: none; }
}

/* ============================ SCENE GAMEPLAY ============================ */

#wheel, #fx {
  position: absolute; left: 0; top: 0;
  width: 1080px; height: 1920px;
  pointer-events: none;
}
#fx { z-index: 90; }

/* Nhãn "Vòng n/3".
   Trước đây chữ "Vòng" và "/3" là hai ảnh cắt từ file thiết kế, chỉ chữ số là
   text. Hai ảnh đó bị lẹm ngay trong bản xuất — nét "V" chạm mép trái, đuôi "g"
   cụt ở đáy, dấu "/" mất một phần bên trái và số 3 bị cắt phẳng bên phải — mà
   kích thước gốc chỉ 86x34 và 33x34 nên phóng lên màn hình lớn là vỡ hạt.
   Nay dựng cả nhãn bằng text với chính bộ chữ của KV (Mirinda Burst), nét sắc
   ở mọi độ phân giải và không còn chỗ nào bị cắt. */
.roundlabel {
  position: absolute;
  left: 0; right: 0;
  display: flex;
  align-items: baseline;
  justify-content: center;
  /* Hở duy nhất trong nhãn là giữa "Vòng" và cụm "n/3" — nên nhãn chỉ có đúng
     hai phần tử con, chữ số phải nằm chung cụm với "/3" chứ không tách ra, kẻo
     đọc thành "Vòng 3 /3". Không ghim bề ngang ô chữ số: nhãn tự căn giữa nên
     đổi vòng chỉ làm xê dịch dưới 2px, ít lộ hơn hẳn khoảng hở giả do ghim. */
  gap: 11px;
  font: italic 800 34px/40px var(--font-round);
  color: var(--c-yellow);
  white-space: nowrap;
  -webkit-text-stroke: 4px var(--c-deep);
  paint-order: stroke fill;
  text-shadow: 0 3px 0 var(--c-deep);
}

/* Gạch đỏ dưới nhãn vòng = thanh thời gian */
.timefill {
  background: var(--c-yellow);
  border-radius: 6px;
  transform-origin: 0 50%;
  transition: transform .1s linear;
  box-shadow: 0 0 16px rgba(252, 247, 4, .55);
}

/* ---------------------------------------------------- lon: cũ -> mới */
/**
 * Ba lon vào màn chơi ở DIỆN MẠO CŨ (artboard 3). Mỗi lần bấm trúng, một lon
 * lột sang DIỆN MẠO MỚI (artboard 4). Đó chính là phần thưởng của game — "mở
 * khoá diện mạo mới" của bộ ba Slim Can.
 *
 * Đây là hai file ảnh khác nhau nằm chồng lên nhau. Lon mới ẩn sẵn (opacity 0)
 * và chỉ hiện đúng giữa cú "Ice Shatter".
 */
/* Thẻ bọc một ô: bóng đổ + lon cũ + lon mới. Xem chú thích trong index.html. */
.can-slot > img { position: absolute; }
.can-shadow { z-index: 0; }

/* Lon cũ đứng nguyên màu thật của nó — không lọc gì cả. Trước đây để đen trắng
   cho ra vẻ "chưa mở khoá", nhưng bộ ba lon cũ vốn đã là một thiết kế hoàn
   chỉnh, làm xám đi chỉ khiến màn chơi trông như hỏng màu. Cái người chơi cần
   thấy là LON ĐỔI, không phải màu quay lại. */
.can-old { z-index: 1; }
.can-new { z-index: 2; opacity: 0; }

/**
 * Hiệu ứng "Ice Shatter" (số 6 trong bộ chuyển cảnh của thương hiệu, xem
 * mirinda-animation.vercel.app). Lon lùi sâu vào trong, nhoè đi, rồi bật ngược
 * ra phía người xem. Cú hoán đổi hai diện mạo đặt đúng mốc 56% — đáy cú lùi,
 * lúc lon ở xa và mờ nhất — nên khách thấy lon "hiện ra" ở diện mạo mới chứ
 * không thấy hai tấm ảnh chuyển cho nhau.
 *
 * Thời lượng, nhịp keyframe và đường cong lấy nguyên từ bản gốc. Chỉ khác một
 * điểm: bản gốc kết ở translateZ(100px) vì đó là card đứng một mình, còn ở đây
 * lon phải về đúng vị trí và kích thước của file thiết kế nên kết ở Z=0 — cú
 * bật ra phía trước vẫn còn, do đường cong tự vọt quá giá trị cuối rồi lùi lại.
 *
 * perspective đặt ngay trong transform thay vì trên phần tử cha: #playCans là
 * div rỗng cao 0px, đặt perspective lên đó thì tâm chiếu rơi vào một điểm vô
 * nghĩa phía trên đầu ba lon.
 *
 * PHÉP CO GIÃN ĐẶT TRÊN THẺ BỌC, không đặt trên từng ảnh. Nhờ vậy bóng đổ, lon
 * cũ và lon mới cùng co về một tâm duy nhất — tâm của chính thẻ bọc. Trước đây
 * mỗi ảnh tự co quanh tâm riêng: bóng nằm trong ảnh nền nên đứng im, còn hai
 * lon lệch nhau 13px nên lúc hoán đổi thấy lon giật ngang.
 */
.can-slot { transform-origin: 50% 50%; }
.can-slot.unlocked { animation: can-shatter .85s cubic-bezier(.68, -.55, .265, 1.55) forwards; }

@keyframes can-shatter {
  0%   { transform: perspective(1400px) translateZ(0) scale(1); }
  40%  { transform: perspective(1400px) translateZ(-300px) scale(.7); }
  100% { transform: perspective(1400px) translateZ(0) scale(1); }
}

/* Hai ảnh lon chỉ còn lo mờ/tỏ và đổi lớp lọc — không đụng gì tới transform,
   nếu không sẽ chồng lên phép co giãn của thẻ bọc.

   Mọi mốc phải liệt kê ĐÚNG cùng một dãy hàm lọc theo cùng thứ tự, kể cả những
   hàm chưa dùng tới (để 0 hoặc trong suốt). Lệch một hàm là trình duyệt bỏ nội
   suy, chuyển phắt từ mốc này sang mốc kia. */
.can-slot.unlocked .can-old { animation: can-fade-out .85s linear forwards; }
.can-slot.unlocked .can-new { animation: can-fade-in  .85s linear forwards; }

@keyframes can-fade-out {
  0% {
    opacity: 1;
    filter: blur(0) drop-shadow(0 0 0 rgba(186, 244, 237, 0));
  }
  40% {
    opacity: 1;
    filter: blur(4px) drop-shadow(0 0 30px rgba(186, 244, 237, 1));
  }
  /* Tắt hẳn tại đáy cú lùi — cùng mốc lon mới bật lên. */
  56%, 100% {
    opacity: 0;
    filter: blur(6px) drop-shadow(0 0 30px rgba(186, 244, 237, 1));
  }
}

@keyframes can-fade-in {
  0%, 40% {
    opacity: 0;
    filter: blur(4px)
            drop-shadow(0 0 30px rgba(186, 244, 237, 1))
            drop-shadow(0 0 0 rgba(var(--glow), 0));
  }
  56% {
    opacity: 1;
    filter: blur(2px)
            drop-shadow(0 0 22px rgba(186, 244, 237, .55))
            drop-shadow(0 0 16px rgba(var(--glow), .35));
  }
  100% {
    opacity: 1;
    /* Kết bằng quầng sáng đúng màu vị, nối liền với chùm đèn ở .can-glow —
       vầng cyan của băng tan hẳn, thay bằng ánh sáng của lon vừa mở khoá. */
    filter: blur(0)
            drop-shadow(0 0 14px rgba(var(--glow), .95))
            drop-shadow(0 0 46px rgba(var(--glow), .55));
  }
}

/* ---------------------------------------------------------- đèn chiếu lon */
/**
 * Sau khi mở khoá, mỗi lon được rọi một chùm đèn màu theo đúng vị — dựng lại
 * cách bộ ba lon được chiếu sáng trong ảnh key visual: chùm sáng đổ từ trên
 * xuống, loe dần, và một vũng sáng đọng dưới chân lon.
 *
 * Màu khai một lần ở đây cho cả lớp đèn lẫn quầng sáng của chính lon, nên hai
 * thứ không bao giờ lệch tông nhau.
 */
/* Khai trên thẻ bọc để cả ba lớp bên trong cùng dùng một màu. */
.can-glow[data-slot="0"], .can-slot[data-slot="0"] { --glow: 255, 162, 58; }   /* hương cam */
.can-glow[data-slot="1"], .can-slot[data-slot="1"] { --glow: 255, 79, 163; }   /* xá xị */
.can-glow[data-slot="2"], .can-slot[data-slot="2"] { --glow: 143, 224, 75; }   /* soda kem */

/**
 * Ảnh mẫu chiếu đèn trên nền tối nên chỉ cần ánh sáng nhạt là nổi. Nền màn chơi
 * ở đây lại là KV đỏ–cyan rực, ánh sáng nhạt phủ lên coi như mất hút — nên dùng
 * `plus-lighter` (cộng thẳng kênh màu, sáng hơn hẳn `screen`) và đẩy cường độ
 * lên cao. Kèm một lớp tối rất mỏng ngay dưới chùm đèn để có nền cho ánh sáng
 * bám vào, giống vai trò của nền tối trong ảnh mẫu.
 */
.can-glow {
  opacity: 0;
  z-index: 0;
}
.can-glow::before, .can-glow::after { mix-blend-mode: plus-lighter; }

/* Lớp tối lót: rất nhẹ, chỉ để chùm sáng có chỗ bám. */
.can-glow > i {
  position: absolute;
  left: 6%; right: 6%; top: 8%; bottom: 2%;
  border-radius: 46% 46% 40% 40% / 30% 30% 22% 22%;
  background: radial-gradient(ellipse at 50% 62%,
    rgba(24, 6, 10, .40) 0%,
    rgba(24, 6, 10, .20) 52%,
    rgba(24, 6, 10, 0)   78%);
  filter: blur(18px);
}
/* Chờ lon lùi ra rồi bật ngược lại xong mới sáng đèn (hoạt hình lon dài .85s). */
.can-glow.on { animation: glow-in .55s ease-out .6s forwards; }
@keyframes glow-in { to { opacity: 1; } }

/* Chùm sáng: hẹp trên, loe xuống dưới.
   Mờ dần cả ở đỉnh chứ không sáng ngay từ dòng đầu — nếu không, mép trên của
   khối clip hiện thành một vệt màu cắt ngang dải cyan của header. */
.can-glow::before {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0; height: 92%;
  clip-path: polygon(34% 0%, 66% 0%, 100% 100%, 0% 100%);
  background: linear-gradient(to bottom,
    rgba(var(--glow), 0)   0%,
    rgba(var(--glow), .70) 22%,
    rgba(var(--glow), .40) 58%,
    rgba(var(--glow), 0)   100%);
  filter: blur(20px);
}

/* Vũng sáng đọng dưới chân lon. */
.can-glow::after {
  content: '';
  position: absolute;
  left: 50%; bottom: 4%;
  width: 82%; height: 15%;
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(ellipse at center,
    rgba(var(--glow), 1)   0%,
    rgba(var(--glow), .70) 40%,
    rgba(var(--glow), 0)   74%);
  filter: blur(9px);
}

/* Thông báo lớn giữa màn (3-2-1, CHÍNH XÁC, TRƯỢT...).
   Dùng Mirinda Burst — đúng bộ chữ tiêu đề của KV, giống hệt nhãn "Vòng n/3"
   ngay phía trên và các dòng chữ vẽ sẵn trong ảnh nền. */
.callout {
  position: absolute;
  left: 0; top: 1215px; width: 1080px;
  text-align: center;
  font: italic 900 128px/1.05 var(--font-round);
  color: var(--c-yellow);
  -webkit-text-stroke: 14px var(--c-deep);
  paint-order: stroke fill;
  text-shadow: 0 12px 0 var(--c-deep);
  opacity: 0;
  transform: scale(.6);
  pointer-events: none;
  z-index: 60;
}
.callout.show { animation: callout-pop .9s cubic-bezier(.2, 1.4, .3, 1) forwards; }
/* Câu dài (vd "MỞ KHÓA GIAO DIỆN!") — hạ cỡ để nằm gọn một dòng trong 1080px.
   Viền và đổ bóng co theo cùng tỷ lệ, giữ đúng độ dày tương đối như cỡ gốc. */
.callout.long {
  font-size: 76px;
  -webkit-text-stroke-width: 9px;
  text-shadow: 0 8px 0 var(--c-deep);
}
.callout.long.miss { text-shadow: 0 8px 0 var(--c-deepdk); }
.callout.miss {
  color: #FFE9E4;
  -webkit-text-stroke-color: var(--c-deepdk);
  text-shadow: 0 12px 0 var(--c-deepdk);
}
@keyframes callout-pop {
  0%   { opacity: 0; transform: scale(.55); }
  22%  { opacity: 1; transform: scale(1.12); }
  38%  { transform: scale(1); }
  78%  { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.04); }
}

/* ============================ SCENE WIN / LOSE ============================ */

.scene.is-active .win-cans {
  animation: win-cans-in .7s cubic-bezier(.2, 1.2, .3, 1) backwards;
}
@keyframes win-cans-in {
  from { opacity: 0; transform: translateY(-60px) scale(.94); }
  to   { opacity: 1; transform: none; }
}

/* Tiêu đề dựng bằng chữ (màn "chưa đạt" không có trong file thiết kế) */
.title-kv {
  font: italic 900 104px/120px var(--font-display);
  text-align: center;
  color: var(--c-yellow);
  -webkit-text-stroke: 12px var(--c-deep);
  paint-order: stroke fill;
  text-shadow: 0 11px 0 var(--c-deep);
}

.lose-sub {
  font: 700 40px/1.35 var(--font-ui);
  text-align: center;
  color: #FFFFFF;
}

.autoreset {
  position: absolute;
  left: 0; bottom: 42px; width: 1080px;
  text-align: center;
  font: 600 28px/1 var(--font-ui);
  color: rgba(255, 255, 255, .72);
  pointer-events: none;
}
.autoreset b { color: var(--c-yellow); }

/* ------------------------------------------------------- chớp đóng băng */
#frost {
  position: absolute; inset: 0;
  background: radial-gradient(circle at 50% 75%,
    rgba(255, 255, 255, .95), rgba(186, 244, 237, .55) 42%, transparent 70%);
  opacity: 0;
  pointer-events: none;
  z-index: 95;
}
#frost.flash { animation: frost-flash .5s ease-out; }
@keyframes frost-flash {
  0%   { opacity: 0; }
  12%  { opacity: 1; }
  100% { opacity: 0; }
}

/* --------------------------------------------------------- giảm chuyển động */
@media (prefers-reduced-motion: reduce) {
  .kvbtn, .kv-float { animation: none !important; }
}
