/* spinJoy · 來源：kiosk-design-system-2026-11-09/css/components.css（Vyin Robot Lobby v4.3.7 設計系統整包，2026-11-09 搬入）。
   spinJoy 改動：2026-11-09 檔尾新增「spinJoy · 商品元件」段；同日換成 Claude Design 定稿 v2（.kv-tag / .kv-prod / .kv-shelf / .kv-ask / .kv-entry / .kv-bundle / .kv-aisle / .kv-go / .kv-compare），交接 design-briefs/product-cards-2026-11-09/handoff-v2/。
   註解裡提到的 assets/campaign 是上一案的素材位置，spinJoy 用 assets/placeholder。
   之後再改請在這裡加一行「YYYY-MM-DD 改了什麼」。 */
/* ============================================================================
   Vyin AI · Robot Lobby UI — Components
   ----------------------------------------------------------------------------
   依賴 tokens.css。所有 class 以 kv- 開頭，BEM：kv-block__element--modifier。

   四層分工：
   · 原語  kv-grow-ring / kv-dot / kv-eyebrow / kv-art / kv-hero
             被多個元件共用的最小單位，改一處全部跟著變。
   · 元件  kv-<component>      只管長相，可以放在任何容器裡。
   觸控規則：可以按的一律是底部的 kv-actions（跟 kv-pill 同一格）；safe area 的卡片永遠不可按。
   · 位置  kv-at-<slot>         把元件放到 1280×800 格線上的固定位置。
   · 版型  kv-screen--<template> 四種畫面骨架，直接子元件自動落到格線，不必再寫 kv-at-*。

   參考稿：design_handoff_vyin_robot_lobby/Vyin Robot Lobby UI.dc.html（2026-09-30）。
   所有數值請看 tokens.css 的來源註記。
   ============================================================================ */

.kv-screen,
.kv-screen *,
.kv-screen::before,
.kv-screen::after,
.kv-side,
.kv-side *,
[class^='kv-'],
[class^='kv-'] * {
  box-sizing: border-box;
}

/* ============================================================== Canvases */

/* Center 1280×800 */
.kv-screen {
  position: relative;
  width: var(--kiosk-center-w);
  height: var(--kiosk-center-h);
  overflow: hidden;
  background: var(--kiosk-surface-base);
  color: var(--kiosk-text-primary);
  font-family: var(--kiosk-font-ui);
  -webkit-font-smoothing: antialiased;
}

/* Side F（前，跟 Center 同面）/ Side B（後，背面）1080×1920 */
.kv-side {
  position: relative;
  width: var(--kiosk-side-w);
  height: var(--kiosk-side-h);
  overflow: hidden;
  background: var(--kiosk-surface-base);
  color: var(--kiosk-text-primary);
  font-family: var(--kiosk-font-ui);
  -webkit-font-smoothing: antialiased;
}

/* Kebbi 臉 1024×600 · proposal（示意，非 Kebbi 實際表情）
   Kebbi 是女媧機器人，表情由它的 SDK 控制、能改多少待實機確認。這個元件只用來在
   原型與矩陣裡示意「哪個畫面對應哪個表情」，不是要廠商重畫 Kebbi 的臉。
   data-emotion：idle / listen / think / speak / countdown / happy / sorry / sleep（對照表見 screens.html 頁尾）
   data-mic：full / cmd / off / dot，驅動臉下方的光條（FOCUS 時收音狀態只靠這條）。 */
.kv-face {
  position: relative;
  width: var(--kiosk-face-w);
  height: var(--kiosk-face-h);
  overflow: hidden;
  background: var(--kiosk-surface-base);
  color: var(--kiosk-text-primary);
  font-family: var(--kiosk-font-display);
}
.kv-face__eyes {
  position: absolute;
  inset: 0 0 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 176px;
  transition:
    transform var(--kiosk-dur-rise) ease,
    translate 900ms cubic-bezier(0.33, 1, 0.68, 1); /* translate = 視線（Micro Moments 01） */
}
.kv-face__eye {
  display: block;
  width: 160px;
  height: 208px;
  border-radius: 80px;
  background: var(--kiosk-text-primary);
  box-sizing: border-box;
  transform-origin: 50% 50%;
  transition:
    width var(--kiosk-dur-rise) ease,
    height var(--kiosk-dur-rise) ease,
    border-radius var(--kiosk-dur-rise) ease,
    transform var(--kiosk-dur-rise) ease,
    opacity var(--kiosk-dur-rise) ease,
    background var(--kiosk-dur-rise) ease,
    box-shadow var(--kiosk-dur-rise) ease;
  animation: kv-face-blink 4.2s ease-in-out infinite;
}
.kv-face__eye:last-child {
  animation-delay: 60ms;
}
.kv-face__mouth {
  position: absolute;
  left: 50%;
  bottom: 112px;
  width: 0;
  height: 20px;
  border-radius: 10px;
  background: var(--kiosk-text-primary);
  transform: translateX(-50%);
  opacity: 0;
  transition:
    width var(--kiosk-dur-rise) ease,
    opacity var(--kiosk-dur-rise) ease;
}
.kv-face__digit {
  position: absolute;
  inset: 0 0 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  font: 800 360px/1 var(--kiosk-font-display);
  opacity: 0;
  transform: scale(0.8);
  transition:
    opacity var(--kiosk-dur-fade) ease,
    transform var(--kiosk-dur-fade) ease;
}
/* 光條：收音狀態。沒有 data-mic 時不顯示。 */
.kv-face__bar {
  position: absolute;
  left: 50%;
  bottom: 32px;
  width: 480px;
  height: 12px;
  border-radius: 6px;
  background: var(--kiosk-text-disabled);
  transform: translateX(-50%);
  opacity: 0;
  transition:
    width var(--kiosk-dur-chrome) ease,
    background var(--kiosk-dur-chrome) ease,
    box-shadow var(--kiosk-dur-chrome) ease,
    opacity var(--kiosk-dur-chrome) ease;
}
.kv-face[data-mic] .kv-face__bar {
  opacity: 1;
}
.kv-face[data-mic='full'] .kv-face__bar {
  background: var(--kiosk-grow-2);
  box-shadow: var(--kiosk-glow-line);
}
.kv-face[data-mic='cmd'] .kv-face__bar {
  width: 240px;
  background: var(--kiosk-grow-2);
}
.kv-face[data-mic='dot'] .kv-face__bar {
  width: 24px;
  background: var(--kiosk-grow-2);
  box-shadow: var(--kiosk-glow-line);
}
.kv-face[data-mic='off'] .kv-face__bar {
  background: var(--kiosk-text-disabled);
}
/* 動作（一次性）：data-gesture="nod" 眼睛往下點一下再回來，播完由 JS 移除屬性。迎賓 / 道別觸發、掃碼完成用。 */
.kv-face[data-gesture='nod'] .kv-face__eyes {
  animation: kv-face-nod 700ms ease-in-out;
}
@keyframes kv-face-nod {
  0%,
  100% {
    translate: 0 0;
  }
  40% {
    translate: 0 56px;
  }
}
/* 表情 */
.kv-face[data-emotion='listen'] .kv-face__eye {
  transform: scale(1.12);
  box-shadow: var(--kiosk-glow-listen);
  animation: none;
}
.kv-face[data-emotion='think'] .kv-face__eyes {
  transform: translate(56px, -48px);
}
.kv-face[data-emotion='think'] .kv-face__eye {
  animation: kv-face-float 1.8s ease-in-out infinite;
}
.kv-face[data-emotion='think'] .kv-face__eye:last-child {
  transform: scale(0.82);
  animation-delay: 200ms;
}
.kv-face[data-emotion='speak'] .kv-face__mouth {
  width: 160px;
  opacity: 1;
  animation: kv-face-speak 420ms ease-in-out infinite alternate;
}
.kv-face[data-emotion='countdown'] .kv-face__eye {
  opacity: 0;
  animation: none;
}
.kv-face[data-emotion='countdown'] .kv-face__digit {
  opacity: 1;
  transform: scale(1);
}
.kv-face[data-emotion='happy'] .kv-face__eye {
  height: 96px;
  border-radius: 80px 80px 0 0;
  background: transparent;
  border: 32px solid var(--kiosk-text-primary);
  border-bottom: 0;
  transform: translateY(-16px);
  animation: none;
}
.kv-face[data-emotion='sorry'] .kv-face__eye {
  height: 136px;
  transform: rotate(-14deg) translateY(24px);
  animation: none;
}
.kv-face[data-emotion='sorry'] .kv-face__eye:last-child {
  transform: rotate(14deg) translateY(24px);
}
.kv-face[data-emotion='sleep'] .kv-face__eye {
  height: 28px;
  opacity: 0.5;
  animation: none;
}
@keyframes kv-face-blink {
  0%,
  93%,
  100% {
    transform: scaleY(1);
  }
  96% {
    transform: scaleY(0.08);
  }
}
@keyframes kv-face-float {
  0%,
  100% {
    translate: 0 0;
  }
  50% {
    translate: 0 -16px;
  }
}
@keyframes kv-face-speak {
  from {
    width: 120px;
    height: 16px;
  }
  to {
    width: 220px;
    height: 36px;
  }
}

/* ============================================================== Primitives
   ---------------------------------------------------------------------------- */

/* Grow 外框 · v4.0（photo v2 回寫，設計師 2026-10-19 全部取代）：
   底變成半透明玻璃後，雙背景 padding-box / border-box 會透出漸層，改成 ::before 圓環 + mask-composite。
   --kv-ring-w 環寬（0 = 沒有環）、--kv-ring-color 環色；元件只覆寫這兩個變數。
   ::before 用 z-index -1 + isolation 疊在底色之上、內容之下，子元素不用動。
   .kv-photo 底是不透明的照片，留舊的雙背景做法。 */
.kv-grow-ring,
.kv-btn,
.kv-pill,
.kv-qr,
.kv-cmd,
.kv-actions__btn {
  --kv-ring-w: 0px;
  --kv-ring-color: var(--kiosk-grow);
  isolation: isolate;
}
.kv-grow-ring,
.kv-btn,
.kv-qr,
.kv-cmd,
.kv-actions__btn {
  position: relative; /* .kv-pill 由版型定位（absolute），不在這裡設 */
}
.kv-grow-ring::before,
.kv-btn::before,
.kv-pill::before,
.kv-qr::before,
.kv-cmd::before,
.kv-actions__btn::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  padding: var(--kv-ring-w);
  background: var(--kv-ring-color);
  -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,
    linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
  transition:
    padding var(--kiosk-dur-press) var(--kiosk-ease),
    background var(--kiosk-dur-press) var(--kiosk-ease);
}
/* 誰有環：CTA 永遠有；對話框平常是半透明白線的環、聆聽時換 Grow；QR 卡只有可掃（--active）時有 Grow（設計師 2026-10-19：QR 一律用 Grow 框 highlight）；
   指令膠囊、動作列的次要按鈕（E04 的「結束對話」）同樣是半透明白線，辨識到指令（--ok）換 Grow */
.kv-grow-ring,
.kv-btn,
.kv-pill,
.kv-qr.kv-qr--active,
.kv-cmd,
.kv-actions__btn {
  --kv-ring-w: var(--kiosk-grow-ring);
}
.kv-pill,
.kv-actions__btn,
.kv-cmd {
  --kv-ring-color: var(--kiosk-line-pill); /* 半透明白線：不管底圖亮暗都「比框內亮一點」 */
}
.kv-pill.kv-pill--listening,
.kv-pill.kv-pill--sent {
  --kv-ring-color: var(--kiosk-grow);
}
.kv-cmd.kv-cmd--ok {
  --kv-ring-color: var(--kiosk-grow);
}
.kv-photo {
  --kv-ring-w: var(--kiosk-grow-border);
  --kv-ring-fill: var(--kiosk-surface-raised);
  border: var(--kv-ring-w) solid transparent;
  background:
    linear-gradient(var(--kv-ring-fill), var(--kv-ring-fill)) padding-box,
    var(--kiosk-grow) border-box;
}

/* 光點 · 圓 + 底色 + 光環。--kv-dot 直徑。 */
.kv-dot,
.kv-mic__dot,
.kv-toast__dot,
.kv-orb {
  --kv-dot: var(--kiosk-mic-dot);
  width: var(--kv-dot);
  height: var(--kv-dot);
  border-radius: 50%;
  flex: none;
}
.kv-dot--full,
.kv-mic--full .kv-mic__dot {
  background: var(--kiosk-grow);
  box-shadow: var(--kiosk-halo-full);
}
.kv-dot--command,
.kv-mic--command .kv-mic__dot {
  background: var(--kiosk-warning);
  box-shadow: var(--kiosk-halo-command);
}
.kv-dot--off,
.kv-mic--off .kv-mic__dot,
.kv-toast__dot {
  background: var(--kiosk-text-disabled);
  box-shadow: none;
}
/* 思考光點 32 · 脈動 .8↔1.1、900ms */
.kv-dot--orb,
.kv-orb {
  --kv-dot: var(--kiosk-orb);
  background: var(--kiosk-grow);
  box-shadow: var(--kiosk-orb-shadow);
  animation: kv-pulse var(--kiosk-dur-pulse) ease-in-out infinite alternate;
}
@keyframes kv-pulse {
  from {
    transform: scale(0.8);
  }
  to {
    transform: scale(1.1);
  }
}

/* Campaign eyebrow · 「現正熱映」。唯一允許用 campaign 色的文字。 */
.kv-eyebrow {
  font: var(--kiosk-type-eyebrow);
  letter-spacing: 0.08em;
  color: var(--kiosk-camp);
  white-space: nowrap;
}

/* 全幅素材層 · 正式素材放 <img> / <video> 進去。 */
.kv-art,
.kv-side__art {
  position: absolute;
  inset: 0;
  overflow: hidden;
  z-index: 0;
}
.kv-art--upper,
.kv-side__art--upper {
  bottom: 420px; /* Side · 上半素材、下半留給邀請（v0.9 後未使用） */
}
.kv-art > img,
.kv-art > video,
.kv-side__art > img,
.kv-side__art > video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* =========================================================== Slideshow
   劇照輪播：多張 img 交替淡入，3s 間隔、1s fade。
   用法：<div class="kv-art kv-slideshow"><img class="kv-slideshow__slide kv-slideshow__slide--active" ...> */
.kv-slideshow__slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 1s ease;
}
.kv-slideshow__slide--active {
  opacity: 1;
}

/* Hero 文字堆 · Welcome / Exit / Moving 封面的大標組。 */
.kv-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 40px;
  text-align: center;
}
.kv-hero--left {
  align-items: flex-start;
  text-align: left;
  gap: var(--kiosk-space-6);
}
.kv-hero__eyebrow {
  font: var(--kiosk-type-hero-eyebrow);
  color: var(--kiosk-text-secondary);
}
.kv-hero__eyebrow--active {
  color: var(--kiosk-text-primary); /* 觸發時整句亮起 */
  animation: kv-brighten var(--kiosk-dur-fade) ease-out;
}
/* 觸發句亮起：從暗、微下方浮上來。eyebrow / sub 共用。 */
@keyframes kv-brighten {
  from {
    opacity: 0.3;
    translate: 0 8px;
  }
}
.kv-hero__title {
  font: var(--kiosk-type-hero-lg);
  color: var(--kiosk-text-primary);
}
.kv-hero__title--xl {
  font: var(--kiosk-type-hero-xl);
}
.kv-hero__sub {
  font: var(--kiosk-type-hero-sub);
  color: var(--kiosk-text-secondary);
}
.kv-hero__sub--active {
  color: var(--kiosk-text-primary);
  animation: kv-brighten var(--kiosk-dur-fade) ease-out;
}
.kv-hero__meta {
  font: var(--kiosk-type-hero-meta);
  color: var(--kiosk-text-muted-light);
}

/* Grow 細線 240×6 · Welcome 觸發時 --wide 960 + 綠光 */
.kv-line {
  width: 240px;
  height: 6px;
  border-radius: 3px;
  background: var(--kiosk-grow);
  flex: none;
}
.kv-line--wide {
  width: 960px;
  box-shadow: var(--kiosk-glow-line);
  animation: kv-line-grow var(--kiosk-dur-rise) ease-out; /* 觸發時從 240 長到 960、綠光亮起 */
}
@keyframes kv-line-grow {
  from {
    width: 240px;
    box-shadow: none;
  }
}

/* ============================================================ Placeholder
   素材佔位：斜紋 + mono 標籤。正式素材進來後整個換掉。 */
.kv-ph {
  position: relative;
  background:
    repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.07) 0 2px, transparent 2px 18px),
    var(--kiosk-camp-bg);
}
.kv-ph--neutral {
  background:
    repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.07) 0 2px, transparent 2px 18px),
    var(--kiosk-border);
}
.kv-ph--camera {
  background:
    repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.07) 0 2px, transparent 2px 18px),
    var(--kiosk-raw-camera-bg);
}
/* 佔位層疊在滿版容器上時，容器的 absolute 要贏過 .kv-ph 的 relative */
.kv-ph.kv-art,
.kv-ph.kv-side__art,
.kv-ph.kv-camera {
  position: absolute;
}
.kv-ph__label {
  position: absolute;
  left: 32px;
  bottom: 28px;
  font: var(--kiosk-type-annot-sm);
  color: rgba(255, 255, 255, 0.5);
  white-space: nowrap;
}
.kv-ph__label--top {
  top: 32px;
  bottom: auto;
  left: 40px;
}
.kv-ph__label--center {
  left: 50%;
  bottom: auto;
  top: 50%;
  transform: translate(-50%, -50%);
  font: var(--kiosk-type-annot);
}
.kv-ph__label--corner {
  left: auto;
  right: var(--kiosk-margin);
  top: 150px;
  bottom: auto;
  font: var(--kiosk-type-annot);
}

/* ================================================================ Top bar */
.kv-topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: var(--kiosk-topbar-h);
}
.kv-topbar--countdown {
  height: var(--kiosk-topbar-count-h);
}
.kv-topbar__left {
  display: flex;
  align-items: center;
  gap: var(--kiosk-space-6);
}
.kv-topbar__meta {
  display: flex;
  align-items: baseline;
  gap: 20px;
}
.kv-logo {
  font: var(--kiosk-type-logo);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
}
.kv-logo--on-media {
  text-shadow: var(--kiosk-text-shadow-logo);
}
.kv-date {
  font: var(--kiosk-type-date);
  color: var(--kiosk-text-secondary);
  white-space: nowrap;
}
.kv-clock {
  font: var(--kiosk-type-clock);
  color: var(--kiosk-text-primary);
}

/* ======================================================= Mic status chip
   Layer 1 · 常駐收音狀態。三態互斥；光點樣式見 Primitives。 */
.kv-mic {
  display: flex;
  align-items: center;
  gap: var(--kiosk-space-3);
}
.kv-mic__label {
  font: var(--kiosk-type-mic);
  color: var(--kiosk-text-secondary);
  white-space: nowrap;
}
/* 壓在媒體上時包一層半透明膠囊 */
.kv-mic--on-media {
  background: var(--kiosk-overlay-media);
  border-radius: var(--kiosk-radius-pill);
  padding: 8px 16px 8px 12px;
}

/* 光條 fallback：只留光點、不帶文字（Focus 層級、Kebbi 光條不可用時） */
.kv-mic--dot .kv-mic__label {
  display: none;
}

/* ============================================================ Hint line
   「重要且常用」的語音指令提示，一次一句，放在底部對話框那格（對話框隱藏時）。
   用在 P03「等一下」與 P06/P07「再拍一次」。辨識到指令時由 .kv-cmd 取代。derived。 */
.kv-hint {
  font: var(--kiosk-type-hint);
  color: var(--kiosk-text-muted-light); /* v4.0：劇照 / 玻璃上的次要文字 #d4d4d4 */
  white-space: nowrap;
  text-shadow: var(--kiosk-text-shadow-logo);
}
/* 底部那格被內容用掉時（Review 頁照片到 y 1016），提示放進 QR 卡白板下方 */
.kv-qr > .kv-hint {
  text-shadow: none;
  color: var(--kiosk-text-tertiary);
}
/* 取像告知（法務 2026-10-14：一行小字即可，不需要同意按鈕）：P06 放最底下置中的一小條，不進 QR 卡也不進照片卡（設計師 2026-10-14） */
.kv-screen > .kv-hint.kv-hint--legal {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 36px;
  transform: none;
  text-align: center;
  color: var(--kiosk-text-muted-light); /* v4.1（設計師 2026-10-21）：原本 --kiosk-text-disabled 灰色被背景吃掉，改偏白 */
  font-size: 18px;
  line-height: 1;
  text-shadow: none;
  z-index: 5;
}
/* 有置底小條的畫面（P06）：卡片縮一點讓出呼吸空間——相紙 600 → 552 寬（約 410 高）、QR xl 456 → 416；小條在 bottom 36，離卡片約 34、離底 36（設計師 2026-10-14：太貼底） */
.kv-screen:has(> .kv-hint--legal) > .kv-safe > .kv-polaroid--review {
  width: 552px;
}
.kv-screen:has(> .kv-hint--legal) > .kv-safe > .kv-qr--xl {
  height: 416px;
}

/* ============================================================ Route pill
   Attraction Moving · 右上「移動中 · 前往 B 點」，三個站點小圓。derived。 */
.kv-route {
  display: inline-flex;
  align-items: center;
  gap: var(--kiosk-space-4);
  padding: 10px 22px 10px 14px;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-overlay-media);
}
.kv-route__dots {
  display: flex;
  gap: var(--kiosk-wave-gap);
}
.kv-route__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--kiosk-raw-dot-future);
}
.kv-route__dot--done {
  background: var(--kiosk-text-primary);
}
.kv-route__dot--next {
  background: var(--kiosk-text-tertiary);
}
.kv-route__text {
  font: var(--kiosk-type-route);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
}

/* =========================================================== AI transcript
   沒有標籤、沒有頭像：位置就是身份。已說出 primary，未說出 disabled。 */
.kv-transcript {
  font: var(--kiosk-type-transcript);
  color: var(--kiosk-text-primary);
  max-height: var(--kiosk-ai-h);
  overflow: hidden;
  text-wrap: pretty;
}
.kv-transcript--one-line {
  max-height: 72px;
}
.kv-transcript__unspoken {
  color: var(--kiosk-text-disabled);
}
.kv-transcript__interrupted {
  color: var(--kiosk-border);
  transition: color var(--kiosk-dur-rise) var(--kiosk-ease);
}
.kv-transcript__hint {
  color: var(--kiosk-text-secondary);
}
/* Karaoke 逐字亮：已說出的字用主色，剩餘維持 disabled */
.kv-karaoke__done {
  color: var(--kiosk-text-primary);
}
.kv-karaoke__rest {
  color: var(--kiosk-text-disabled);
}
.kv-transcript__unspoken--done {
  color: var(--kiosk-text-primary);
}
/* 全螢幕媒體上的字幕版 */
.kv-transcript--caption {
  font: var(--kiosk-type-caption);
  max-height: none;
  text-shadow: var(--kiosk-text-shadow-media);
}
/* 預告字幕：停 3s 後 400ms 淡出，讓人專心看片（README：caption fades after 3s）。
   重新加上 class 就會重播；樣式指南捲到該畫面時會重播一次。 */
.kv-transcript--fade {
  animation: kv-caption-out 400ms var(--kiosk-ease) var(--kiosk-dur-caption) forwards;
}
/* 預告開場兩行（v4.2）：停 6.5s（--kiosk-dur-caption-long） */
.kv-transcript--fade-long {
  animation: kv-caption-out 400ms var(--kiosk-ease) var(--kiosk-dur-caption-long) forwards;
}
@keyframes kv-caption-out {
  to {
    opacity: 0;
  }
}

/* ========================================================= Status (思考)
   放在 AI 區同一位置或其下緣。延遲 > 0.8s 才顯示。 */
.kv-status {
  display: flex;
  align-items: center;
  gap: 14px;
  height: 48px;
  padding-left: var(--kiosk-space-3);
}
.kv-status__label {
  font: var(--kiosk-type-status);
  color: var(--kiosk-text-secondary);
  white-space: nowrap;
}

/* ===================================================== Sentence progress
   回答超過 2 行時拆句；3 段 48×8，目前句用 Grow。 */
.kv-progress {
  display: flex;
  gap: var(--kiosk-space-3); /* derived */
  align-items: center;
}
.kv-progress__seg {
  width: var(--kiosk-progress-w);
  height: var(--kiosk-progress-h);
  border-radius: 4px;
  background: var(--kiosk-border);
}
.kv-progress__seg--active {
  background: var(--kiosk-grow);
}

/* ======================================================= User dialog pill
   Layer 2 · 召喚式對話框。沒有「你」標籤。 */
.kv-pill {
  display: flex;
  align-items: center;
  gap: 20px;
  width: var(--kiosk-pill-w);
  height: var(--kiosk-pill-h);
  padding: 0 var(--kiosk-pill-pad-x);
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-pill); /* v4.0：玻璃底 + 3px 圓環（見 Primitives），原本實色 + 2px inset */
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
}
.kv-pill__placeholder {
  flex: 1;
  font: var(--kiosk-type-user-pill);
  color: var(--kiosk-text-muted-light); /* v4.0：玻璃上的次要文字 #d4d4d4 */
  white-space: nowrap;
  overflow: hidden;
}
/* 聆聽中：圓環換 Grow（見 Primitives）+ 光暈，高 96，即時逐字稿 + 游標 + 波形 */
.kv-pill--listening {
  height: var(--kiosk-pill-h-listen);
  gap: var(--kiosk-space-6);
  box-shadow: var(--kiosk-glow-listen);
}
/* 已送出（v4.1，2026-10-21）：對話框第三態。觀眾說完 / 點完、系統還在處理時用——外觀同聆聽（Grow 環 + 光暈），
   顯示剛剛的那句（或點的那顆），沒有游標與波形（不是在聽），右側放狀態字。用在 P01a「正在啟動」、A04「Vyin 正在思考」、E05「重新連線中」。
   背景要不要壓暗由畫面決定（P01a 壓，A04 / E05 不壓）。狀態字可以先 hidden（A04 超過 1.5s 才出）。 */
.kv-pill--sent {
  height: var(--kiosk-pill-h-listen);
  gap: var(--kiosk-space-6);
  box-shadow: var(--kiosk-glow-listen);
}
.kv-pill--sent > .kv-pill__placeholder,
.kv-pill--sent > .kv-wave,
.kv-pill--sent .kv-caret {
  display: none;
}
.kv-pill__status {
  flex: none;
  height: auto;
  padding-left: 0;
}
.kv-pill:not(.kv-pill--sent) > .kv-pill__status,
.kv-pill__status[hidden] {
  display: none;
}
.kv-pill__live {
  flex: 1;
  display: flex;
  align-items: center;
  gap: var(--kiosk-space-2);
  font: var(--kiosk-type-user-live);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
  overflow: hidden;
}
.kv-caret {
  width: var(--kiosk-caret-w);
  height: var(--kiosk-caret-h);
  border-radius: 2px;
  background: var(--kiosk-text-primary);
  flex: none;
  animation: kv-blink 1s steps(1) infinite;
}
@keyframes kv-blink {
  50% {
    opacity: 0;
  }
}
/* Photo idle：標題用 hero 字級，底部獨立 CTA 按鈕 + 小提示 */
.kv-transcript--hero {
  font: var(--kiosk-type-transcript-hero);
  max-height: 168px; /* 64px × 1.3 × 2 行 = 166.4 */
}
.kv-cta-hint {
  font: var(--kiosk-type-cta-hint);
  color: var(--kiosk-text-muted-light);
}

/* ============================================================ Action bar
   觸控規則（設計師 2026-09-30 定案）：**可以按的東西一律住在底部對話框那一格**，
   語音時是 .kv-pill，觸控時是 .kv-actions；safe area 只放資訊，卡片永遠不可按。
   1280×144、按鈕等寬、主要選項在最右、一屏一個。按下：填色升一階 + 縮 97%、120ms。 */
.kv-actions {
  display: flex;
  gap: var(--kiosk-actions-gap);
  width: var(--kiosk-pill-w);
  height: var(--kiosk-pill-h-listen);
}
.kv-actions__btn {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--kiosk-space-3);
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-pill); /* v4.0：跟對話框同一個面（玻璃 + border 色圓環，見 Primitives）；設計師 2026-10-19：E04 的「結束對話」要像沒有 Grow 的對話框 */
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  font: var(--kiosk-type-action);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  transition:
    transform var(--kiosk-dur-press) var(--kiosk-ease),
    background-color var(--kiosk-dur-press) var(--kiosk-ease);
}
.kv-actions__cat {
  font: var(--kiosk-type-tag);
  color: var(--kiosk-text-muted-light);
}
/* 決策型動作列：主要按鈕用 CTA 樣式，跟次要按鈕並排 */
.kv-actions > .kv-btn {
  flex: 1;
  font: var(--kiosk-type-action);
}
/* 只有一顆時置中（設計師 2026-10-06 新增）：同動作列的主要鈕尺寸、Grow 外框，寬一半。P01b 用。 */
.kv-actions--single {
  justify-content: center;
}
.kv-actions--single > .kv-btn {
  flex: 0 0 calc((100% - var(--kiosk-actions-gap)) / 2);
}
.kv-actions__btn:active,
.kv-actions__btn--down,
.kv-actions__btn.is-pressed {
  --kv-ring-color: var(--kiosk-line-pressed);
  background: var(--kiosk-glass-tap);
  transform: scale(0.97);
}

/* ================================================================ Waveform
   8 條 8px 寬、圓角 4，顏色照 Grow 色站；高度 12–56 動態。 */
.kv-wave {
  display: flex;
  align-items: center;
  gap: var(--kiosk-wave-gap);
  height: var(--kiosk-wave-bar-max);
  flex: none;
}
.kv-wave__bar {
  width: var(--kiosk-wave-bar-w);
  height: var(--kiosk-wave-bar-min);
  border-radius: 4px;
  animation: kv-wave 1.1s ease-in-out infinite alternate;
}
.kv-wave__bar:nth-child(1) {
  background: var(--kiosk-grow-1);
  animation-delay: 0ms;
}
.kv-wave__bar:nth-child(2) {
  background: var(--kiosk-grow-2);
  animation-delay: -150ms;
}
.kv-wave__bar:nth-child(3) {
  background: var(--kiosk-grow-2);
  animation-delay: -300ms;
}
.kv-wave__bar:nth-child(4) {
  background: var(--kiosk-grow-3);
  animation-delay: -450ms;
}
.kv-wave__bar:nth-child(5) {
  background: var(--kiosk-grow-4);
  animation-delay: -600ms;
}
.kv-wave__bar:nth-child(6) {
  background: var(--kiosk-grow-4);
  animation-delay: -750ms;
}
.kv-wave__bar:nth-child(7) {
  background: var(--kiosk-grow-5);
  animation-delay: -900ms;
}
.kv-wave__bar:nth-child(8) {
  background: var(--kiosk-grow-5);
  animation-delay: -1050ms;
}
@keyframes kv-wave {
  from {
    height: var(--kiosk-wave-bar-min);
  }
  to {
    height: var(--kiosk-wave-bar-max);
  }
}
/* 太吵 / 多人說話：灰階、不動 */
.kv-wave--grey .kv-wave__bar {
  background: var(--kiosk-text-disabled);
  animation: none;
  height: 8px;
}
.kv-wave--grey .kv-wave__bar:nth-child(2n) {
  height: 10px;
}
.kv-wave--grey .kv-wave__bar:nth-child(4) {
  height: 12px;
}
.kv-wave--grey .kv-wave__bar:nth-child(1),
.kv-wave--grey .kv-wave__bar:nth-child(5),
.kv-wave--grey .kv-wave__bar:nth-child(8) {
  height: 8px;
}

/* ============================================================== CTA button
   一屏只有一個。v4.0：玻璃底 + 3px Grow 圓環（見 Primitives）+ CTA 光暈；按下縮 95%、光暈加強、環加粗（Handoff §3）。
   按下態由 JS 在 touchstart 加 .is-pressed（:active 在觸控螢幕會閃），保持 ≥120ms 再切畫面。 */
.kv-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 16px 36px;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-pill);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: var(--kiosk-glow-cta);
  font: var(--kiosk-type-cta);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
  cursor: pointer;
  transition:
    transform var(--kiosk-dur-press) var(--kiosk-ease),
    box-shadow var(--kiosk-dur-press) var(--kiosk-ease);
}
.kv-btn.is-pressed {
  --kv-ring-w: var(--kiosk-grow-ring-pressed);
  transform: scale(0.95);
  box-shadow: var(--kiosk-glow-cta-pressed);
}
.kv-btn--lg {
  font: var(--kiosk-type-cta-lg);
  padding: 20px 48px; /* derived · 按 34→56 等比 */
}
.kv-btn--hero {
  font: var(--kiosk-type-cta-hero);
  padding: 24px 64px; /* derived · 特別重要的 CTA，用在 Photo idle 等全螢幕場景 */
}

/* =============================================================== Safe area
   所有卡片 / QR / CTA / 照片的容器。橫向 flex，gap 24。 */
.kv-safe {
  display: flex;
  align-items: flex-start; /* 卡片與 QR 卡同高 268，不撐滿 safe area（設計師 2026-10-06；752 → 800 多出的 48 留在下面） */
  gap: var(--kiosk-card-gap);
  width: var(--kiosk-ai-w);
  height: var(--kiosk-safe-h);
}
.kv-safe--one-line {
  height: var(--kiosk-safe-h-1line);
}
.kv-safe--extended {
  height: var(--kiosk-safe-h-ext);
}
.kv-safe--one-line-extended {
  height: var(--kiosk-safe-h-1line-ext);
}
.kv-safe--center {
  justify-content: center;
}
/* chips + QR 並排：chips 靠左堆疊、QR 靠右（E03 查不到） */
.kv-safe--chips-qr {
  align-items: flex-start;
}
.kv-safe--chips-qr > .kv-chips {
  position: static;
  flex: 1;
}

/* =================================================================== Cards
   Info card：只在資訊比 AI 說的多時才出現。卡片永遠不可按，也不加 Grow 外框；
   Grow 外框只出現在 .kv-actions、.kv-btn、.kv-qr--active、.kv-pill--listening。 */
.kv-card {
  flex: 1;
  height: var(--kiosk-qr-card); /* 同 QR 卡 */
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: var(--kiosk-card-pad-y) var(--kiosk-card-pad-x);
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-glass-info); /* v4.0：玻璃 .42 + blur + 1px 細線（Handoff §2 .card-info），原本實色 #171717 */
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
  min-width: 0;
}
.kv-card__label {
  font: var(--kiosk-type-card-label);
  color: var(--kiosk-text-muted-light); /* v4.0：玻璃上的次要文字 #d4d4d4 */
}
.kv-card__value {
  font: var(--kiosk-type-card-value);
  color: var(--kiosk-text-primary);
}
.kv-card__value--md {
  font: var(--kiosk-type-card-value-md);
}
.kv-card__value--num {
  font: var(--kiosk-type-card-num);
}
/* 建議卡：2px 內框（v4.0 改成可點框那條線） */
/* v4.3.4 ④ P06 左欄的「同框禮」小卡（設計師 2026-11-04 選 B）：chips 底下、法務小字上面（y 480–612），斗篷毯小圖 + 「合照換斗篷毯 / 怎麼換，QR 裡有步驟」；詳細步驟在 QR 的活動頁 */
.kv-event-strip {
  position: absolute;
  left: 56px;
  top: 480px;
  width: 440px;
  height: 132px;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 10px 22px 10px 14px;
  box-sizing: border-box;
  border-radius: 24px;
  background: var(--kiosk-glass-info);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
  z-index: 3;
}
.kv-event-strip > img {
  flex: none;
  height: 108px;
  width: 108px;
  object-fit: contain;
  filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.4));
}
.kv-event-strip > div {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}
.kv-event-strip b {
  font: 700 28px/1.2 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
}
.kv-event-strip span {
  font: 500 22px/1.3 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
}
/* 活動好康卡（v4.3.4，A05e / TA；設計師 2026-11-03：海報與斗篷毯照片直接上）：既有 .kv-card 改橫排，左邊預購禮（兩張海報疊貼）、右邊同框禮（斗篷毯去背圖）；
   文字沿用 __label，標題 __title 32；兩個活動同時出現、不分上映前後。素材 assets/campaign/event/（設計師 2026-11-03 給） */
.kv-card--event {
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  gap: 24px;
  padding: 20px 24px;
}
.kv-event__text > .kv-card__label {
  white-space: nowrap;
}
.kv-event__item {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 18px;
  min-width: 0;
}
.kv-event__item + .kv-event__item {
  padding-left: 24px;
  box-shadow: inset 1px 0 0 var(--kiosk-line-info);
}
.kv-event__posters {
  position: relative;
  flex: none;
  width: 150px;
  height: 200px;
}
.kv-event__posters img {
  position: absolute;
  top: 8px;
  width: 108px;
  height: 162px;
  object-fit: cover;
  border-radius: 6px;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.45);
}
.kv-event__posters img:first-child {
  left: 0;
  rotate: -5deg;
}
.kv-event__posters img:last-child {
  left: 42px;
  top: 22px;
  rotate: 4deg;
}
.kv-event__cloak {
  flex: none;
  width: 164px;
  height: 200px;
  object-fit: contain;
  filter: drop-shadow(0 10px 18px rgba(0, 0, 0, 0.45));
}
.kv-event__text {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}
.kv-event__title {
  font: 700 30px/1.25 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
}
/* 觸控模式的活動卡跟語音同一個版面（設計師 2026-11-03：觸控版撐到 360 會破版）：safe area 回 316、卡與 QR 都 268 */
.kv-screen--touch.is-event > .kv-safe {
  height: var(--kiosk-safe-h);
  align-items: flex-start;
}
.kv-screen--touch.is-event > .kv-safe > .film-v {
  align-items: flex-start;
}
.kv-screen--touch.is-event > .kv-safe .kv-card--event {
  height: var(--kiosk-qr-card); /* 觸控頁的卡與 QR 包在 .film-v 裡，不是 .kv-safe 的直接子層 */
}
.kv-screen--touch.is-event > .kv-safe .kv-qr {
  width: var(--kiosk-qr-card);
  height: var(--kiosk-qr-card);
  --kiosk-qr-code: calc(var(--kiosk-qr-card) - 132px);
}
/* v4.3.7 活動階段（設計師 2026-11-04）：還沒開始（上映前的同框禮）掛「11/26 開始」（送完狀態 11/05 刪除） */
.kv-event__badge {
  align-self: flex-start;
  margin-top: 4px;
  padding: 4px 12px;
  border-radius: 999px;
  font: 700 18px/1.2 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
  box-shadow: inset 0 0 0 1.5px var(--kiosk-line-info);
}
.kv-event-strip > img.is-poster {
  object-fit: cover;
  width: 76px;
  margin: 0 16px;
  border-radius: 6px;
}
.kv-card--outlined {
  box-shadow: inset 0 0 0 2px var(--kiosk-line-tap);
}
/* 小型可點卡（v4.0 新增 · Handoff §2 .card-tap）：觸控面板按鈕，右下角 64px 白圓鈕 */
.kv-card--tap {
  background: var(--kiosk-glass-tap);
  box-shadow: inset 0 0 0 2px var(--kiosk-line-tap), var(--kiosk-shadow-card);
  cursor: pointer;
  transition:
    transform var(--kiosk-dur-press) var(--kiosk-ease),
    background var(--kiosk-dur-press) var(--kiosk-ease),
    box-shadow var(--kiosk-dur-press) var(--kiosk-ease);
}
.kv-card--tap.is-pressed {
  transform: scale(0.97);
  background: rgba(255, 255, 255, 0.12);
  box-shadow: inset 0 0 0 2px var(--kiosk-line-pressed), var(--kiosk-shadow-card);
}
.kv-tap-arrow {
  position: absolute;
  right: 40px;
  bottom: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--kiosk-text-primary);
  color: var(--kiosk-surface-base);
  font: 700 28px/1 var(--kiosk-font-ui);
}

/* ================================================================= QR card
   固定 400×400，永遠在 safe-area 最右。 */
.kv-qr {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  width: var(--kiosk-qr-card);
  height: var(--kiosk-qr-card);
  padding: 28px;
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-glass-info); /* v4.0：跟資訊卡同一個玻璃面；可掃時加 Grow 圓環（見 Primitives） */
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
}
.kv-qr__title {
  font: var(--kiosk-type-qr-title);
  color: var(--kiosk-text-muted-light); /* v4.0：#d4d4d4 */
  white-space: nowrap;
}
.kv-qr__plate {
  padding: var(--kiosk-qr-plate-pad);
  border-radius: var(--kiosk-radius-plate);
  background: var(--kiosk-white);
}
.kv-qr__code {
  display: block;
  width: var(--kiosk-qr-code);
  height: var(--kiosk-qr-code);
  /* 佔位棋盤；正式 QR 以 <img> 或 <canvas> 取代這個 div */
  background: repeating-conic-gradient(var(--kiosk-surface-base) 0 25%, var(--kiosk-white) 0 50%)
    0 0/18px 18px;
}
/* 可掃的 QR：Grow 圓環（見 Primitives）+ 卡片級光暈（設計師 2026-10-19：QR 一律用 Grow 框 highlight） */
.kv-qr--active {
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info), var(--kiosk-glow-card);
}
}
.kv-qr--active .kv-qr__title {
  color: var(--kiosk-text-muted-light);
}
/* 延伸內容卡（P08 三張 QR 都是可掃的內容）：標題亮一階但不加外框。derived。 */
.kv-qr--offer .kv-qr__title {
  color: var(--kiosk-text-muted-light);
}
/* 440：Exit 唯一 CTA */
.kv-qr--lg {
  width: var(--kiosk-qr-card-lg);
  height: var(--kiosk-qr-card-lg);
}
.kv-qr--lg .kv-qr__title {
  font: var(--kiosk-type-qr-title-lg);
}
.kv-qr--lg .kv-qr__code {
  width: var(--kiosk-qr-code-lg);
  height: var(--kiosk-qr-code-lg);
  background-size: 20px 20px;
}
/* 照片 Review 頁：卡片撐滿照片右側剩餘寬與 684 高，標題 40/700 + 320 白板 */
.kv-qr--xl {
  flex: 1;
  width: auto;
  height: var(--kiosk-photo-h-lg); /* 跟 812×456 的照片框同高（設計師 2026-10-06），不隨 safe area 撐滿 */
  gap: var(--kiosk-space-6);
}
.kv-qr--xl .kv-qr__title {
  font: var(--kiosk-type-qr-title-xl);
  color: var(--kiosk-text-primary);
}
.kv-qr--xl .kv-qr__plate {
  padding: var(--kiosk-qr-plate-pad-lg);
  border-radius: var(--kiosk-radius-plate-lg);
}
.kv-qr--xl .kv-qr__code {
  width: var(--kiosk-qr-code-xl);
  height: var(--kiosk-qr-code-xl);
  background-size: 28px 28px;
}

/* ================================================================== Chips
   建議提問。 */
.kv-chips {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--kiosk-space-4);
}
.kv-chip {
  display: inline-flex;
  align-items: center;
  padding: 20px 32px;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-tap); /* v4.0：玻璃 .16 + 1.5px 白 .40，原本實色 + 2px #262626 */
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1.5px var(--kiosk-line-tap);
  font: var(--kiosk-type-chip);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
  transition:
    transform var(--kiosk-dur-press) var(--kiosk-ease),
    background var(--kiosk-dur-press) var(--kiosk-ease),
    box-shadow var(--kiosk-dur-press) var(--kiosk-ease);
}
.kv-chip.is-pressed {
  transform: scale(0.95);
  background: rgba(255, 255, 255, 0.34);
  box-shadow: inset 0 0 0 2px var(--kiosk-line-pressed);
  font-weight: 700;
}

/* ============================================================ Command pill
   COMMAND 模式的精簡對話框 720×112。辨識到指令 → ✓ 立刻執行；非指令 → 提示 1.5s。 */
.kv-cmd {
  display: flex;
  align-items: center;
  gap: var(--kiosk-space-5);
  width: var(--kiosk-cmd-w);
  height: var(--kiosk-cmd-h);
  padding: 0 var(--kiosk-space-7);
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-pill); /* v4.0：玻璃 + 3px 圓環（見 Primitives），原本實色 .92 + 2px inset */
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
}
.kv-cmd--ok {
  box-shadow: var(--kiosk-glow-listen);
}
.kv-cmd__check {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--kiosk-check);
  height: var(--kiosk-check);
  border-radius: 50%;
  flex: none;
  background: var(--kiosk-success);
  color: var(--kiosk-surface-base);
  font: 900 20px/1 var(--kiosk-font-ui);
}
.kv-cmd__text {
  flex: 1;
  font: var(--kiosk-type-cmd);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
  overflow: hidden;
}
.kv-cmd__tag {
  font: var(--kiosk-type-tag);
  color: var(--kiosk-text-muted-light);
  white-space: nowrap;
}
.kv-cmd__hint {
  flex: 1;
  font: var(--kiosk-type-cmd-hint);
  color: var(--kiosk-text-muted-light);
  white-space: nowrap;
}
.kv-cmd__options {
  font: var(--kiosk-type-tag);
  color: var(--kiosk-text-tertiary);
  white-space: nowrap;
}

/* =================================================================== Toast
   OFF 模式：不叫出對話框，只浮一行 3s。 */
.kv-toast {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 16px 32px;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-overlay-pill);
  box-shadow: inset 0 0 0 2px var(--kiosk-raw-touch-border);
}
.kv-toast__text {
  font: var(--kiosk-type-toast);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
}

/* ============================================================ Media bar
   預告播放中的底部資訊：左片名、右「隨時可以問我」膠囊；下方進度條。derived（README 未列）。 */
.kv-media-bar {
  display: flex;
  align-items: center;
  gap: var(--kiosk-space-6);
}
.kv-media-bar__title {
  font: var(--kiosk-type-media-title);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
}
.kv-media-bar__hint {
  font: var(--kiosk-type-media-hint);
  color: var(--kiosk-text-muted-light);
  background: var(--kiosk-overlay-media);
  border-radius: var(--kiosk-radius-pill);
  padding: 10px 20px;
  white-space: nowrap;
}
/* 進度條：軌 20% 白、進度 primary。--kv-progress 0–100。 */
.kv-media-progress {
  height: var(--kiosk-media-progress-h);
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.2);
  --kv-progress: 0;
}
.kv-media-progress::before {
  content: '';
  display: block;
  height: 100%;
  width: calc(var(--kv-progress) * 1%);
  border-radius: 4px;
  background: var(--kiosk-text-primary);
}

/* ======================================================== Countdown pill
   系統倒數一律在頂列右側，取代日期時間；此時底部對話框隱藏。
   環：--kv-progress 為 0–100 的百分比（inline style 或 JS 設定）。 */
.kv-countdown {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 8px 22px 8px 8px;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-surface-raised);
  --kv-progress: 100;
}
.kv-countdown__ring {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--kiosk-ring);
  height: var(--kiosk-ring);
  border-radius: 50%;
  flex: none;
  background: conic-gradient(
    var(--kiosk-grow-4) 0 calc(var(--kv-progress) * 1%),
    var(--kiosk-border) 0
  );
}
.kv-countdown__ring::after {
  content: '';
  width: var(--kiosk-ring-inner);
  height: var(--kiosk-ring-inner);
  border-radius: 50%;
  background: var(--kiosk-surface-raised);
}
.kv-countdown__text {
  font: var(--kiosk-type-countdown-pill);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
}
.kv-countdown__num {
  font: var(--kiosk-type-countdown-pill-num);
}

/* ================================================================== Scrims
   獨立元素版。用版型（kv-screen--media / --cover / --standby）時由 ::before/::after 自動產生。 */
.kv-scrim {
  position: absolute;
  left: 0;
  right: 0;
  pointer-events: none;
  z-index: 1;
}
.kv-scrim--top {
  top: 0;
  height: var(--kiosk-scrim-h);
  background: var(--kiosk-scrim-top);
}
.kv-scrim--top-tall {
  top: 0;
  height: var(--kiosk-scrim-h-tall);
  background: var(--kiosk-scrim-top);
}
.kv-scrim--bottom {
  bottom: 0;
  height: var(--kiosk-scrim-h);
  background: var(--kiosk-scrim-bottom);
}
.kv-scrim--cover {
  top: 0;
  bottom: 0;
  background: var(--kiosk-scrim-cover);
}
.kv-dim {
  position: absolute;
  inset: 0;
  background: var(--kiosk-dim);
  pointer-events: none;
  z-index: 4;
}

/* ======================================================== Camera / photo */
.kv-camera {
  position: absolute;
  inset: 0;
  z-index: 0;
}
/* 相機外框：8px 環，inset 28，圓角 36，用 mask 挖空中間。v4.0：改灰（#525252），Grow 環讓給真正會取用的取景框（設計師 2026-10-19） */
.kv-camera__frame {
  position: absolute;
  inset: var(--kiosk-camera-inset);
  border: var(--kiosk-grow-border-camera) solid transparent;
  border-radius: var(--kiosk-radius-camera);
  background: var(--kiosk-text-disabled) border-box;
  -webkit-mask:
    linear-gradient(#000 0 0) padding-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#000 0 0) padding-box,
    linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
  z-index: 2;
}
/* 取景框 v4.0：跟最終輸出的洞同比例、同圓角（tokens --kiosk-hole-*），一直是 6px Grow 環（mask 挖空），畫面正中。
   原本「白虛線 → 站好變綠實線」拿掉：不等人進框，倒數本身就是信號（設計師 2026-10-19） */
.kv-camera__guide {
  position: absolute;
  left: calc((var(--kiosk-center-w) - var(--kiosk-guide-w)) / 2);
  top: var(--kiosk-guide-top);
  width: var(--kiosk-guide-w);
  height: var(--kiosk-guide-h);
  border: var(--kiosk-guide-border) solid transparent;
  border-radius: var(--kiosk-hole-radius);
  background: var(--kiosk-grow) border-box;
  -webkit-mask:
    linear-gradient(#000 0 0) padding-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#000 0 0) padding-box,
    linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
  z-index: 2;
}
/* 取景框外壓暗：跟取景框同大小、同圓角的透明塊，用超大的 box-shadow 蓋掉外面（鏡頭之上、環與角色之下）。
   強調框內才是最後會取用的畫面（設計師 2026-10-19） */
.kv-camera__mask {
  position: absolute;
  left: calc((var(--kiosk-center-w) - var(--kiosk-guide-w)) / 2);
  top: var(--kiosk-guide-top);
  width: var(--kiosk-guide-w);
  height: var(--kiosk-guide-h);
  border-radius: var(--kiosk-hole-radius);
  box-shadow: 0 0 0 2000px var(--kiosk-camera-mask);
  pointer-events: none;
  z-index: 1;
}
/* 會遮到人的角色疊在取景框內（連拍第一張；設計師 2026-10-19：只放角色、不放框）。
   跟取景框同大小的裁切容器；裡面放整張照片框圖層（story-strip-frame.png），把它的上格（80,140 / 920×690）對到取景框，
   格外的部分被容器裁掉，所以不需要另外去背的角色圖。顯示與否由 .is-overlay 決定（film 在 P02 加、第二張拿掉） */
.kv-camera__overlay {
  position: absolute;
  left: calc((var(--kiosk-center-w) - var(--kiosk-guide-w)) / 2);
  top: var(--kiosk-guide-top);
  width: var(--kiosk-guide-w);
  height: var(--kiosk-guide-h);
  border-radius: var(--kiosk-hole-radius);
  overflow: hidden;
  pointer-events: none;
  z-index: 2;
  display: none;
}
.kv-screen.is-overlay > .kv-camera__overlay {
  display: block;
}
/* 疊角色時 Grow 環要蓋在角色上面（設計師 2026-10-29）：角色貼到框邊的部分被環壓住，看起來是「在框裡」而不是浮在框上 */
.kv-screen.is-overlay > .kv-camera__guide {
  z-index: 3;
}
.kv-camera__overlay > img,
.kv-camera__overlay > video {
  clip-path: var(--kv-ov-clip, none); /* 只留大佔位：該款可以裁掉擠進格子邊角的小素材（js/frames.js viewfinderKeepX） */
  position: absolute;
  left: calc(var(--kiosk-guide-w) * -80 / 920);
  top: calc(var(--kiosk-guide-h) * var(--kv-ov-y1, -140) / 690);
  width: calc(var(--kiosk-guide-w) * 1080 / 920);
  filter: drop-shadow(0 12px 24px rgba(0, 0, 0, 0.45));
}
/* v4.1（設計師 2026-10-21）：連拍的照片框素材是給人互動的，第一張取景要疊（完整不透明，人自己躲）；第二張預設不疊
   （比莉施法下格只露落葉、背包、logo 一點點，看不懂），之後的款下格有大素材才疊（js/frames.js overlay2），裁到下格。
   有動態版就疊透明影片 loop（js/frames.js 放進來），靜態圖藏起來 */
.kv-screen.is-strip-2 > .kv-camera__overlay > img,
.kv-screen.is-strip-2 > .kv-camera__overlay > video {
  top: calc(var(--kiosk-guide-h) * var(--kv-ov-y2, -850) / 690);
}
/* 單張：照片格在 top 590（月亮框的比莉站在照片下緣、會蓋到） */
.kv-camera__overlay--single > img,
.kv-camera__overlay--single > video {
  top: calc(var(--kiosk-guide-h) * var(--kv-ov-ys, -590) / 690);
}
.kv-camera__overlay > video {
  opacity: 0;
}
.kv-camera__overlay.kv-vid-on > video {
  opacity: 1;
}
.kv-camera__overlay.kv-vid-on > img {
  visibility: hidden;
}
/* 連拍第二張：右上 REC 2/2 小標記（.is-strip-2 時出現） */
.kv-camera__rec {
  position: absolute;
  top: 48px;
  right: var(--kiosk-margin);
  display: none;
  align-items: center;
  gap: 10px;
  font: 600 18px/1 var(--kiosk-font-mono);
  letter-spacing: 0.12em;
  color: var(--kiosk-text-primary);
  z-index: 6;
}
.kv-camera__rec::before {
  content: '';
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #ff3b30;
  animation: kv-rec-blink 1s steps(2, start) infinite;
}
.kv-screen.is-strip-2 .kv-camera__rec {
  display: flex;
}
@keyframes kv-rec-blink {
  to {
    opacity: 0.2;
  }
}
/* 倒數數字 268px 置中 */
.kv-camera__digit {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font: var(--kiosk-type-countdown);
  color: var(--kiosk-text-primary);
  text-shadow: var(--kiosk-text-shadow-digit);
  pointer-events: none;
  z-index: 3;
}
/* 快門白閃 92%，--kiosk-dur-flash（v4.1 700ms） */
.kv-flash {
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.92);
  pointer-events: none;
  z-index: 5; /* 頂列（6）留在白閃上面 */
  animation: kv-flash var(--kiosk-dur-flash) ease-out forwards;
}
.kv-flash--hold {
  animation: none; /* 靜態畫面用 */
}
@keyframes kv-flash {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
/* 照片預覽框：4px Grow 外框（見 Primitives），圓角 32。照片放 <img>，佔位放 .kv-ph */
.kv-photo {
  --kv-ring-w: var(--kiosk-grow-border-photo);
  --kv-ring-fill: var(--kiosk-border);
  position: relative;
  flex: none;
  width: var(--kiosk-photo-w);
  height: var(--kiosk-photo-h);
  border-radius: var(--kiosk-radius-card);
  overflow: hidden;
}
.kv-photo--lg {
  width: var(--kiosk-photo-w-lg);
  height: var(--kiosk-photo-h-lg);
}
.kv-photo > img,
.kv-photo > video,
.kv-photo > .kv-ph {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: calc(var(--kiosk-radius-card) - var(--kiosk-grow-border-photo));
}

/* ========================================================= Side screens
   設計師 2026-09-30 定案：Side 預設只放整張海報（.kv-side > .kv-art），不疊我們的字。
   2026-10-05 確認兩片是前後不是左右：前（F）配合 Center，Photo / Attraction 放素材牆；後（B）永遠整張海報。
   照片牆是 README 的 nice-to-have 變體。Medium fidelity，硬體尺寸確認後再細調。 */
/* v4.3 退場（設計師 2026-10-28 拿掉照片牆；index.html 樣本已刪），只剩 transitions-explore.html 探索頁在用，探索頁清掉時整段一起刪。
   Side F · 照片牆（v4.1，設計師 2026-10-20；取代 v4.0 的素材牆，全部待命時段）
   Claude Design 定稿「2a 拍立得吐出來」：四張限動框疊著（頂張 720×1280，其餘三張只露邊、各微傾），每 7 秒一張新的從下緣
   吐上來（0–1.1s 快出慢停）、落到頂（1.1–1.6s）、照片從暗褐顯影（0.6–3.8s，只對照片、框不變暗——框是辨識點），
   其他三張往下沉一層（1.4s）、最底那張淡出（0.9s）。其餘時間完全靜止：不跑馬燈、不 Ken Burns、不閃。
   用自己人拍好的死圖（目前劇照假圖），不要時間戳、人名、「最新」——不是即時放映。標題「一起拍一張」、底部法務一行（措辭待法務）。
   不放按鈕、不放 QR。交付是 35s loop 影片（5 張 × 7s，第 0 秒靜止 7 秒才吐第一張，頭尾同一格）。
   版位由 JS 設 transform（prototype.html 的 photo wall）；規格頁用 inline style 擺靜止首格。 */
.kv-side-photos {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--kiosk-surface-base);
  z-index: 2;
}
.kv-side-photos__title {
  position: absolute;
  left: var(--kiosk-margin);
  right: var(--kiosk-margin);
  top: 72px;
  margin: 0;
  text-align: center;
  font: var(--kiosk-type-side-title);
  color: var(--kiosk-text-primary);
  letter-spacing: 0.02em;
}
.kv-side-photos__foot {
  position: absolute;
  left: var(--kiosk-margin);
  right: var(--kiosk-margin);
  bottom: var(--kiosk-space-8);
  margin: 0;
  text-align: center;
  font: var(--kiosk-type-side-meta);
  color: var(--kiosk-text-secondary);
}
.kv-side-photos > .kv-story.kv-side-photos__card {
  --story-w: 720px;
  position: absolute;
  left: 180px;
  top: 300px;
  border-radius: var(--kiosk-radius-tile);
  box-shadow: var(--kiosk-shadow-photo);
  transform-origin: 50% 50%;
  transition:
    transform 1400ms var(--kiosk-ease),
    opacity 900ms var(--kiosk-ease);
}
.kv-side-photos > .kv-story.kv-side-photos__card.is-jump {
  transition: none;
}
/* 底下三張壓暗分層（設計師 2026-10-20：同背景疊在一起糊成一片；第一版用 --kiosk-dim 最多 62% 還太清楚）：
   用螢幕底色（--kiosk-surface-base）疊在整張卡上，深度由 --kv-depth 控制（頂張 0、往下 .65 / .8 / .9），跟著下沉一起 1.4s 過渡 */
.kv-side-photos > .kv-story.kv-side-photos__card::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--kiosk-surface-base);
  opacity: var(--kv-depth, 0);
  transition: opacity 1400ms var(--kiosk-ease);
  pointer-events: none;
  z-index: 3;
}
.kv-side-photos > .kv-story.kv-side-photos__card.is-jump::after {
  transition: none;
}
.kv-side-photos__card .kv-story__slot > img {
  transition: filter 3200ms cubic-bezier(0.4, 0, 0.2, 1);
}
.kv-side-photos__card.is-dev .kv-story__slot > img {
  transition: none;
  filter: brightness(0.22) sepia(0.7) saturate(0.35) contrast(0.6);
}
/* Side F · 打光態（v4.1，設計師 2026-10-20；取代 v4.0 的站位 / 看鏡頭 / 白閃三張）
   拍照當成一段連續過程：P02 站位進、P05b 吐出出，連拍中間不回牆。整段亮著是為了相機的曝光（只在快門亮 450ms，
   LCD 來不及、自動曝光也來不及，每張亮度不穩）也為了不嚇到人。
   畫面上的東西少、靜、深色面積小：上方一句「看鏡頭」（連拍第二張「換個姿勢」），中間跟 Center 同步的倒數數字，其他留白。
   快門那一刻 .is-flash：底從暖白拉到純白約 700ms 再回來，當快門回饋，不是從暗到亮。不放 logo、海報、法務小字。 */
.kv-side-light {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 120px;
  padding-top: 420px;
  background: var(--kiosk-side-light);
  color: var(--kiosk-side-light-text);
  z-index: 2;
  transition: background var(--kiosk-dur-flash) var(--kiosk-ease);
}
.kv-side-light.is-flash {
  background: var(--kiosk-side-light-peak);
  transition: none;
}
.kv-side-light__text {
  font: var(--kiosk-type-side-title);
}
/* 副標（v4.2，設計師 2026-10-28：新框每款都有角色在動，提示放 Side F 才看得到，Center 太小）：貼在標題下面、比標題淡 */
.kv-side-light__sub {
  margin-top: -84px;
  font: 700 52px/1.3 var(--kiosk-font-ui);
  opacity: 0.75;
}
.kv-side-light__digit {
  font: var(--kiosk-type-side-digit);
  min-height: 420px;
  opacity: 0;
  transition: opacity var(--kiosk-dur-fade) var(--kiosk-ease);
}
.kv-side-light.is-count .kv-side-light__digit {
  opacity: 1;
}

/* Side 的一行提示 .kv-marquee（v5「機器人能幹嘛」最上面那句；v4.3 起 Side F 使用中態也用，所以搬出 @promo-handoff 段當共用元件）：
   34/700 紙白、兩側奶金箭頭往上點一下（2.4s）、置中、頂部 150。 */
.kv-marquee {
  position: absolute;
  left: 0;
  right: 0;
  top: 150px;
  width: max-content;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 14px;
  height: 88px;
  font: 700 34px/1 var(--kiosk-font-ui);
  color: var(--kiosk-promo-paper);
  white-space: nowrap;
  z-index: 2;
}
.kv-marquee__arrow {
  color: var(--kiosk-camp);
  animation: kv-marquee-nudge 2.4s ease-in-out infinite;
}
@keyframes kv-marquee-nudge {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-6px); }
}
/* Side F 使用中態（v4.3，設計師 2026-10-30）：有人點了 Center 之後，觀眾會不確定該看 Side F 還是 Center（使用者測試）。
   使用中 Side F 仍是海報 A，但**壓暗四成**退成背景，**頂部**一行「在中間螢幕跟我聊 ↓」淡入、停 8 秒淡出（視線由上往下導到 Center 一次就好），
   之後維持壓暗海報；拍照時照舊換打光 / 倒數 / 拍完。輸出成 side-f-in-use.mp4（9s，停最後一格 = 壓暗海報 A）。 */
.kv-side-inuse {
  position: absolute;
  inset: 0;
  background: var(--kiosk-surface-base);
  overflow: hidden;
}
.kv-side-inuse__poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.kv-side-inuse__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(0, 0, 0, 0.92) 0, rgba(0, 0, 0, 0.7) 260px, rgba(0, 0, 0, 0) 720px), /* 頂部壓到接近全黑：提示字坐在海報的片頭字與 logo 上，不能疊（設計師 2026-10-30） */
    rgba(0, 0, 0, 0.4);
}
/* 提示字 = 「機器人能幹嘛」最上面那句的同一個元件 .kv-marquee（v5 起：34/700、紙白、奶金 ↑ 兩側、頂部 150；設計師 2026-10-30：要一模一樣）。
   Center 在 Side F 上方，箭頭往上。 */


/* Side 劇照牆（v4.2，設計師 2026-10-28 加回待命輪播：迪士尼很喜歡）。從 v3.3 的 Side F 素材牆 .kv-side-wall 拿回來，標題改「歡迎光臨魔法秘境」。
   上面片名、下面 2 × 3 劇照 + 一張橫幅大圖；兩面 Side 待命輪播的 ③（海報之後，8s），輸出成 side-stills-1080x1920.png */
.kv-side-wall {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: 24px;
  gap: 24px;
  z-index: 2;
  background: var(--kiosk-surface-base);
}
.kv-side-wall__title {
  font: var(--kiosk-type-side-title);
  color: var(--kiosk-text-primary);
  padding: 40px 24px 0;
}
.kv-side-wall__grid {
  flex: 1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  min-height: 0;
}
.kv-side-wall__tile {
  width: 100%;
  height: 100%;
  min-height: 0;
  object-fit: cover;
  border-radius: var(--kiosk-radius-tile);
}
.kv-side-wall__tile--featured {
  grid-column: 1 / -1;
}

/* Side 直式預告示意（v4.2，設計師 2026-10-28）：直式預告機器人端已經有了，這包只放示意畫面（黑底白字）。兩面 Side 待命輪播的 ④ */
.kv-side-wait {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 40px;
  background: #000;
  color: var(--kiosk-text-primary);
}
.kv-side-wait__title {
  font: 900 120px/1 var(--kiosk-font-ui);
  letter-spacing: 0.06em;
}
.kv-side-wait__sub {
  font: 500 40px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-secondary);
}

/* Side F · 拍完態（v4.1，設計師 2026-10-20，取代同天上午的「顯影態」：框的形狀就是照片的承諾，Side F 放不了使用者的照片，
   放流光還是會讓人等照片，所以不放任何相紙形狀）。工程條件：Side F 只放預製素材（圖 / 影片，可控時、可停最後一格、即時切換），
   最後交付是一支影片，這裡用 HTML 示意節奏（P05b 觸發）：
   0.0s 打光態熄掉變黑（燈關了、拍完了），眼睛回到 Center 正在彈出來的相紙 · 0.3s 火光從底邊升起（3s，慶祝）
   3.4s 火光轉稀疏（幾顆慢慢飄，畫面不死）、浮出「照片在上面的 QR 裡」+ 往上箭頭 → 停到 P09。P06 / PHONE / E10 都停著。
   P09 .is-send：火光最後亮一下再淡出（1.2s）接回牆；重拍回 P02 直接切打光態。 */
.kv-side-done {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--kiosk-surface-base);
  z-index: 2;
}
.kv-side-done__msg {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 56px;
  padding-bottom: 200px;
  font: var(--kiosk-type-side-title);
  text-align: center; /* 一行會貼齊 1080 兩邊，拆兩行（2026-10-21） */
  color: var(--kiosk-text-primary);
  opacity: 0;
  transition: opacity var(--kiosk-dur-rise) var(--kiosk-ease);
  z-index: 4;
}
/* 拍完態第三行（v4.3.4 ⑤，設計師 2026-11-04）：帶同框禮一句，小一級、次要色 */
.kv-side-done__sub {
  margin-top: -8px;
  font: 500 56px/1.2 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
}
.kv-side-done.is-msg .kv-side-done__msg {
  opacity: 1;
}
.kv-side-done__arrow {
  width: 240px;
  height: auto;
}
.kv-side-done__arrow path {
  fill: none;
  stroke: currentColor;
  stroke-width: 28;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* 火光整片不遮（Center 版有下半的遮罩與 560px 的上升距離，是給 800 高的畫布）；--sparse 是提示字出來之後留的那幾顆 */
.kv-side-done > .kv-embers {
  z-index: 3;
  -webkit-mask-image: none;
  mask-image: none;
}
.kv-side-done > .kv-embers > .kv-ember {
  bottom: var(--y, 12%); /* 一部分從中段（--y: 48%）起飛，不用跑整片才到上緣 */
  animation-name: kv-ember-rise-side;
}
.kv-side-done > .kv-embers--sparse {
  opacity: 0.55;
  animation: kv-fade-in 1200ms ease-out;
}
/* v4.3 ① 帶路（設計師 2026-10-30，第四版：跟 Center 的 M01 對齊）：Side 1080×1920 版的 .kv-move——同一張劇照模糊壓暗 + 對話底的 scrim、
   Grow 三箭頭轉成朝上（前進方向）、字放大 1.4 倍（Side 在 1–5m 外看）、底部同一顆玻璃膠囊提示。Side B 文案 = Center；Side F 給前面的人「借過一下」。 */
.kv-side-move {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--kiosk-surface-base);
}
.kv-side-move__bg {
  position: absolute;
  inset: -80px;
  width: calc(100% + 160px);
  height: calc(100% + 160px);
  object-fit: cover;
  object-position: 50% 35%;
  filter: blur(var(--kiosk-dialog-blur)) brightness(var(--kiosk-dialog-dim)) saturate(var(--kiosk-dialog-saturate));
}
.kv-side-move__scrim {
  position: absolute;
  inset: 0;
  background: var(--kiosk-dialog-scrim);
}
.kv-side-move > .kv-move {
  display: flex;
  gap: 28px;
  padding-bottom: 160px;
}
.kv-side-move__arrows { /* 三個朝上的 › 疊成一柱、由下往上接力亮（跟 Center 的三個 › 同一組 keyframes） */
  display: flex;
  flex-direction: column-reverse;
  align-items: center;
  gap: 6px;
  margin-bottom: 12px;
}
.kv-side-move__chev {
  width: 150px;
  height: auto;
  display: block;
  animation: kv-move-arrow 1.2s ease-in-out infinite;
}
.kv-side-move__chev:nth-child(2) {
  animation-delay: 0.2s;
}
.kv-side-move__chev:nth-child(3) {
  animation-delay: 0.4s;
}
.kv-side-move > .kv-move > .kv-move__title {
  font-size: 184px;
}
.kv-side-move > .kv-move > .kv-move__sub {
  font-size: 42px;
}
.kv-side-move > .kv-move__hint {
  display: block;
  bottom: 160px;
  padding: 24px 44px;
  font-size: 30px;
}
.kv-side-guide .kv-side-done__arrow {
  animation: kv-side-guide-nudge 3s ease-in-out infinite;
}
@keyframes kv-side-guide-nudge {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-40px); }
}
/* 回牆（P09）：黑底 2.4s 溶成透明讓牆從底下透出來，字 600ms 先走，火光留在牆上再飄 3s 才淡掉——用火光把兩個畫面串起來（設計師 2026-10-20：硬切太生硬） */
.kv-side-done {
  transition: background-color 2400ms ease-in-out;
}
.kv-side-done.is-send {
  background-color: transparent;
}
.kv-side-done.is-send > .kv-embers--sparse {
  opacity: 0.9;
  transition: opacity 600ms ease-out;
}
.kv-side-done.is-send .kv-side-done__msg {
  opacity: 0;
  transition-duration: 600ms;
}
/* Side F 的火光一路飄到頂、出畫面時還亮著（設計師 2026-10-20：看起來像從 Side F 跑到上面的 Center）；Center 那邊用 --from-below 從下緣接進來 */
@keyframes kv-ember-rise-side {
  0% {
    transform: translate3d(0, 0, 0);
    opacity: 0;
  }
  12% {
    opacity: var(--op);
  }
  100% {
    transform: translate3d(var(--drift), -2000px, 0);
    opacity: var(--op);
  }
}
/* Side · Exit 延伸邀請（v2.5）
   無字海報滿版 + 全頁遮罩 + 置中 QR 卡（Grow 外框）。
   設計師：「畫面上還是要有視覺讓人馬上辨識跟電影的關係」。
   工程師備註：如果 Side 接 HTML 的成本太高，可以退回純 JPG 海報版本（posterA / posterB）。 */
.kv-side-exit {
  position: absolute;
  inset: 0;
  z-index: 2;
}
.kv-side-exit > .kv-art > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.kv-side-exit__scrim {
  position: absolute;
  inset: 0;
  background: rgba(10, 10, 10, 0.72);
}
.kv-side-exit__body {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 56px;
  padding: 160px 80px;
  text-align: center;
}
.kv-side-exit--top .kv-side-exit__body { justify-content: flex-start; }
.kv-side-exit--bottom .kv-side-exit__body { justify-content: flex-end; }
.kv-side-exit__cta {
  font: 700 56px/1.3 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
}
.kv-side-exit__hint {
  font: var(--kiosk-type-side-meta);
  color: var(--kiosk-text-secondary);
}

/* 媒體控制（v2.9）
   Center：點螢幕 = 暫停/繼續（出現大播放鈕覆蓋）；「結束預告」小按鈕帶 Grow 框。
   Side：不可觸控，純預覽。暫停/停止狀態跟著 Center 走。 */

/* 結束預告按鈕（Center 右下角，跟 media-bar 片名底對齊）。
   2026-10-22 設計師要大一點：先試 56，看過後定跟 chips 一樣（高 68、字用 --kiosk-type-chip 28、圖示 16），觸控元件同一級。 */
.kv-media-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  height: 68px;
  padding: 0 32px;
  border-radius: var(--kiosk-radius-pill);
  border: none;
  background: var(--kiosk-surface-raised);
  color: var(--kiosk-text-primary);
  font: var(--kiosk-type-chip);
  cursor: pointer;
  transition: background 120ms ease, transform 120ms ease;
  white-space: nowrap;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
}
.kv-media-btn:hover {
  background: #3a3a3a;
}
.kv-media-btn:active {
  background: #525252;
  transform: scale(0.97);
}
.kv-media-btn__icon {
  width: 18px;
  height: 18px;
  flex: none;
}
.kv-media-btn--stop .kv-media-btn__icon::before {
  content: '';
  display: block;
  width: 16px;
  height: 16px;
  border-radius: 2px;
  background: currentColor;
}

/* v4.2 預告畫面乾淨（設計師 2026-10-27）：片名列與進度條跟著上面的字走——開場句 / A06v 提示 / 斷線說明在的時候出現，字淡掉就一起淡掉，
   只剩預告（.is-bare）；點畫面暫停（.is-paused）時再出現。頂列與上下兩層遮罩（給字讀的暗漸層）也一起淡掉（設計師 2026-10-28）。「結束預告」從頭到尾都在：有片名列時跟片名底對齊（bottom 88），
   沒有時往下移到預告的下黑邊正中（bottom 17，--kiosk-media-btn-bottom-bare），不擋畫面（設計師 2026-10-28）。暫停時片名列、進度條、結束預告都在暫停遮罩（z 8）上面，結束預告點得到。 */
.kv-screen--media > .kv-media-bar,
.kv-screen--media > .kv-media-progress,
.kv-screen--media > .kv-topbar,
.kv-screen--media::before,
.kv-screen--media::after {
  transition: opacity 400ms var(--kiosk-ease); /* 跟字幕淡出同速 */
}
.kv-screen--media > .kv-media-controls {
  transition: transform 400ms var(--kiosk-ease);
}
.kv-screen--media.is-bare:not(.is-paused) > .kv-media-bar,
.kv-screen--media.is-bare:not(.is-paused) > .kv-media-progress,
.kv-screen--media.is-bare:not(.is-paused) > .kv-topbar,
.kv-screen--media.is-bare:not(.is-paused)::before,
.kv-screen--media.is-bare:not(.is-paused)::after {
  opacity: 0;
}
.kv-screen--media.is-bare:not(.is-paused) > .kv-media-bar,
.kv-screen--media.is-bare:not(.is-paused) > .kv-media-progress {
  pointer-events: none; /* 透明了也不能擋住移到下黑邊的結束預告 */
}
.kv-screen--media > .kv-media-controls {
  z-index: 3; /* 在片名列與進度條（z 2）之上 */
}
.kv-screen--media.is-bare:not(.is-paused) > .kv-media-controls {
  transform: translateY(calc(var(--kiosk-media-bar-bottom) - var(--kiosk-media-btn-bottom-bare)));
}
.kv-screen--media.is-paused > .kv-media-bar,
.kv-screen--media.is-paused > .kv-media-progress,
.kv-screen--media.is-paused > .kv-media-controls,
.kv-screen--media.is-paused > .kv-topbar {
  z-index: 9;
}

/* 暫停覆蓋層：點螢幕觸發，顯示大播放鈕 + 半透明暗幕 */
.kv-media-pause {
  position: absolute;
  inset: 0;
  z-index: 8;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease;
  cursor: pointer;
}
.kv-media-pause.active {
  opacity: 1;
  pointer-events: auto;
}
/* 大播放鈕：圓形 Grow 外框 + 光暈，跟 DS 的 .kv-btn CTA 同語言 */
.kv-media-pause__play {
  width: 120px;
  height: 120px;
  border-radius: 50%;
  border: var(--kiosk-grow-border) solid transparent;
  background:
    linear-gradient(var(--kiosk-surface-raised), var(--kiosk-surface-raised)) padding-box,
    var(--kiosk-grow) border-box;
  box-shadow: var(--kiosk-glow-cta);
  display: flex;
  align-items: center;
  justify-content: center;
}
.kv-media-pause__play::before {
  content: '';
  display: block;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 22px 0 22px 38px;
  border-color: transparent transparent transparent var(--kiosk-text-primary);
  margin-left: 8px; /* 視覺置中補償 */
}

/* ===================================================== Micro Moments（v1.8）
   設計師 2026-10-05 確認的十個情境。Kebbi 那半是示意（實機換 SDK 的表情與動作），Center / Side 那半是正式規格。
   全部是「加 class 就播一次」或「設 CSS 變數就跟著動」，JS 只負責時機與事件；接法見 README §5.7。 */

/* 01 無人互動 · 視線：--kv-gx / --kv-gy（px）由 JS 設在 .kv-face 與 .kv-screen 上。
   眼睛跟著看；cover 畫面加 .kv-screen--gaze 時，圖往反方向微移（像海報在被看）。久了沒人：Kebbi sleep + .kv-screen--asleep 讓 CTA 呼吸。 */
.kv-face {
  --kv-gx: 0px;
  --kv-gy: 0px;
}
.kv-face__eyes {
  translate: var(--kv-gx) var(--kv-gy);
}
.kv-screen--gaze > .kv-art > img,
.kv-screen--gaze > .kv-art > .kv-slideshow__slide {
  translate: calc(var(--kv-gx, 0px) * -0.35) 0;
  transition: translate 1200ms cubic-bezier(0.33, 1, 0.68, 1);
}
.kv-screen--asleep > .kv-btn--hero {
  animation: kv-breathe 3200ms ease-in-out infinite;
}
@keyframes kv-breathe {
  0%,
  100% {
    box-shadow: var(--kiosk-glow-cta);
  }
  50% {
    box-shadow: 0 0 72px rgba(31, 111, 224, 0.75);
  }
}
/* 02 有人靠近 · 招呼句從人的那一側滑進來（Kebbi 用 --kv-gx 轉向 + data-gesture="nod"） */
.kv-transcript--from-left {
  animation: kv-slide-l 600ms cubic-bezier(0.33, 1, 0.68, 1);
}
.kv-transcript--from-right {
  animation: kv-slide-r 600ms cubic-bezier(0.33, 1, 0.68, 1);
}
@keyframes kv-slide-l {
  from {
    opacity: 0;
    translate: -96px 0;
  }
}
@keyframes kv-slide-r {
  from {
    opacity: 0;
    translate: 96px 0;
  }
}
/* 03 提到《魔法秘境》· Kebbi 金眼 1s（.kv-face--gold）；Center：一道窄的暖光帶斜掃過素材（.kv-screen--sweep，z 3 在素材與遮罩上、文字下，1100ms）
   + 素材亮度抬一下、換進來的海報從 1.06 推回 1（.kv-slideshow__slide--enter）、標題金光一閃（.kv-transcript--lit）、
   chips 逐顆退場換句再進場並亮金邊（.kv-chip--out / --in / --lit）；Side F 切海報 A 10s 由 JS 做。
   設計師 2026-10-06：第一版整片米色罩住畫面、文字跟著變色，太粗；改成只打在素材上的窄光帶。 */
.kv-face--gold .kv-face__eye {
  background: var(--kiosk-camp);
  box-shadow: 0 0 72px var(--kiosk-camp);
}
/* 光帶：寬 200% 的 ::after，帶在正中（gradient 44–56%），用 translate 從右邊畫面外推到左邊畫面外（±60% 自身寬 = ±1536px），
   終點一定在畫面外。設計師 2026-10-06：第一版用 background-position 百分比，斜角漸層算不準、最後停在畫面左側才被移除。 */
.kv-screen--sweep::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: -50%;
  width: 200%;
  z-index: 3;
  pointer-events: none;
  mix-blend-mode: screen;
  background: linear-gradient(
    104deg,
    transparent 42%,
    oklch(0.84 0.12 68 / 0.22) 46%,
    oklch(0.97 0.08 80 / 0.85) 50%,
    oklch(0.84 0.12 68 / 0.22) 54%,
    transparent 58%
  );
  animation: kv-sweep 2400ms cubic-bezier(0.65, 0, 0.35, 1) forwards; /* 1100ms 太快沒有快慢，拉到 2.4s、慢進快中慢出 */
}
@keyframes kv-sweep {
  from {
    translate: 60% 0;
  }
  to {
    translate: -60% 0;
  }
}
.kv-screen--sweep > .kv-art {
  animation: kv-art-lift 2600ms cubic-bezier(0.45, 0, 0.25, 1);
}
@keyframes kv-art-lift {
  0% {
    filter: brightness(1);
  }
  30% {
    filter: brightness(1.22) saturate(1.12);
  }
  100% {
    filter: brightness(1);
  }
}
.kv-screen--sweep .kv-slideshow__slide {
  transition-duration: 2200ms;
}
.kv-slideshow__slide--enter {
  animation: kv-slide-enter 3600ms cubic-bezier(0.16, 0.6, 0.2, 1) forwards;
}
@keyframes kv-slide-enter {
  from {
    scale: 1.06;
  }
  to {
    scale: 1;
  }
}
.kv-transcript--lit {
  animation: kv-text-lit 2600ms cubic-bezier(0.45, 0, 0.25, 1) 300ms both;
}
@keyframes kv-text-lit {
  0% {
    text-shadow: 0 0 0 transparent;
  }
  25% {
    text-shadow: 0 0 28px oklch(0.84 0.12 68 / 0.9);
  }
  100% {
    text-shadow: 0 0 0 transparent;
  }
}
.kv-chip--out {
  opacity: 0;
  translate: 0 -8px;
  transition:
    opacity 360ms cubic-bezier(0.55, 0, 1, 0.45),
    translate 360ms cubic-bezier(0.55, 0, 1, 0.45);
}
.kv-chip--in {
  animation: kv-chip-in 720ms cubic-bezier(0.16, 0.8, 0.2, 1) both;
}
@keyframes kv-chip-in {
  from {
    opacity: 0;
    translate: 0 10px;
  }
  to {
    opacity: 1;
    translate: 0 0;
  }
}
.kv-chip--lit {
  animation: kv-chip-lit 3600ms cubic-bezier(0.45, 0, 0.25, 1) both;
}
.kv-chip--in.kv-chip--lit {
  animation:
    kv-chip-in 720ms cubic-bezier(0.16, 0.8, 0.2, 1) both,
    kv-chip-lit 3600ms cubic-bezier(0.45, 0, 0.25, 1) both;
}
@keyframes kv-chip-lit {
  0%,
  20% {
    box-shadow: inset 0 0 0 2px var(--kiosk-camp);
  }
  100% {
    box-shadow: inset 0 0 0 2px var(--kiosk-border);
  }
}
/* 04 提到 Disney · 星星眼 + LED 跑一圈 Grow（.kv-face--star .kv-face--led-run，1.2s 後移除）；Center 上飄星點 .kv-spark（JS 生 20 顆、2s 後移除） */
.kv-face--star .kv-face__eye {
  clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
  border-radius: 0;
  width: 200px;
  height: 200px;
  background: var(--kiosk-grow-3);
  animation: none;
}
.kv-face--led-run .kv-face__bar {
  background: var(--kiosk-grow);
  background-size: 300% 100%;
  animation: kv-led-run 1200ms linear;
}
@keyframes kv-led-run {
  from {
    background-position: 100% 0;
  }
  to {
    background-position: -100% 0;
  }
}
/* 設計師 2026-10-06：原本的星點往上飄太像火光，先改四芒星又跟主視覺不搭；定案「光塵」：
   七十多顆細碎微粒像魔法粉塵被光照到，固定位置快閃、微微往上飄 28px，少數幾顆大一點。
   大小 / 延遲 / 時長 / 橫漂由 JS 設在 --size / --delay / --dur / --dx；--n 閃幾次。 */
.kv-spark {
  position: absolute;
  width: var(--size, 3px);
  height: var(--size, 3px);
  border-radius: 50%;
  background: #fff;
  box-shadow:
    0 0 calc(var(--size, 3px) * 2) var(--kiosk-grow-3),
    0 0 calc(var(--size, 3px) * 5) rgb(244 251 208 / 0.5);
  mix-blend-mode: screen;
  z-index: 7;
  pointer-events: none;
  opacity: 0;
  animation: kv-dust var(--dur, 900ms) ease-in-out var(--delay, 0ms) var(--n, 2);
}
@keyframes kv-dust {
  0% {
    opacity: 0;
    translate: 0 0;
  }
  30% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    translate: var(--dx, 0px) -28px;
  }
}
/* 05 拍照 P02 站進框 · Kebbi 光圈眼（.kv-face--aperture）。v4.1：Side F 是打光態整段不變（站位人形填滿那段已拿掉） */
.kv-face__eye {
  position: relative;
}
.kv-face--aperture .kv-face__eye {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  background: transparent;
  border: 34px solid var(--kiosk-text-primary);
  animation: none;
}
.kv-face--aperture .kv-face__eye::after {
  content: '';
  position: absolute;
  inset: 44px;
  border-radius: 50%;
  background: var(--kiosk-text-primary);
}
/* 06 拍照完成 · P05b 拍立得：底圖壓暗（.kv-art--dim），相紙從底部吐出 900ms、照片 2.4s 顯影。
   接著 P06 加 .kv-screen--arrive：照片用 FLIP 從相紙位置飛到格子（transform 由 JS 量測後設定，transition 在這裡）、白框淡出、QR 從右滑入、頂列與 AI 句淡入。 */
.kv-art--dim > img {
  filter: brightness(0.35);
}
/* 拍立得相紙 · 複製自 Vyin 官網活動頁 C01（設計師 2026-10-06 給的 hexed_html.zip / vyin-polaroid.html）。官網那份後續改動不會同步過來。
   原版是 480 寬的手機卡（Instax Wide 99:62、字 7.5–10px）；這裡放大到 820 寬、照片 16:9、字按比例放大，材質 / 月相 / 規格字樣 / 曝光列照搬。
   .kv-polaroid 本身仍是「從底部吐出」的動畫容器；.kv-polaroid__photo 的 class 名不變（P06 的 FLIP 靠它量位置）。 */
.kv-polaroid {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 820px;
  padding: 34px 34px 48px;
  display: flex;
  flex-direction: column;
  border-radius: 8px;
  background-image:
    radial-gradient(120% 85% at 16% 6%, rgb(255 255 255 / 0.06) 0%, rgb(255 255 255 / 0.015) 34%, rgb(255 255 255 / 0) 62%),
    linear-gradient(180deg, rgb(255 255 255 / 0.02) 0%, rgb(0 0 0 / 0) 26%, rgb(0 0 0 / 0.22) 100%),
    linear-gradient(to right, #34312d 0%, #10100f 17%, #0a0a09 82%, #050505 100%);
  box-shadow:
    0 -1px 0 rgb(255 255 255 / 0.08),
    -1px 0 0 rgb(255 255 255 / 0.055),
    0 1px 0 rgb(255 228 190 / 0.075),
    1px 0 0 rgb(255 228 190 / 0.045),
    0 0 0 1px #030303 inset,
    1px 1px 2px rgb(255 255 255 / 0.07) inset,
    -1px -2px 3px rgb(0 0 0 / 0.69) inset,
    0 40px 100px rgb(0 0 0 / 0.6);
  translate: -50% 120%;
  rotate: -2deg;
  z-index: 7;
  animation: kv-polaroid-up 900ms cubic-bezier(0.33, 1, 0.68, 1) forwards;
}
.kv-polaroid::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='d' filterUnits='userSpaceOnUse' x='0' y='0' width='140' height='140' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='1' seed='5' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='20' intercept='-11.2'/%3E%3C/feComponentTransfer%3E%3CfeComponentTransfer%3E%3CfeFuncA type='discrete' tableValues='0 1'/%3E%3C/feComponentTransfer%3E%3CfeGaussianBlur stdDeviation='0.55'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23d)'/%3E%3C/svg%3E");
  background-size: 100px 100px;
  opacity: 0.11;
}
.kv-polaroid > * {
  position: relative;
  z-index: 1;
}
@keyframes kv-polaroid-up {
  to {
    translate: -50% -56px;
  }
}
.kv-polaroid__photo {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 2px;
  background: #141414;
  box-shadow: 0 0 0 1px rgb(214 178 121 / 0.22);
}
.kv-polaroid__photo > img,
.kv-polaroid__photo > .kv-ph {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: brightness(0.04) saturate(0) contrast(1.4);
  animation: kv-develop 2400ms ease-out 600ms forwards;
}
@keyframes kv-develop {
  55% {
    filter: brightness(0.55) saturate(0.35) contrast(1.25);
  }
  to {
    filter: none;
  }
}
/* 上緣：兩條細線夾五顆月相 */
.kv-polaroid__head {
  display: flex;
  align-items: center;
  gap: 20px;
  margin-top: 14px;
}
.kv-polaroid__rule {
  flex: 1;
  height: 1px;
  background-image: linear-gradient(90deg, rgb(111 75 39 / 0.38) 0%, rgb(111 75 39 / 0.62) 28%, rgb(111 75 39 / 0.4) 55%, rgb(111 75 39 / 0.58) 84%, rgb(111 75 39 / 0.42) 100%);
}
.kv-polaroid__moons {
  flex: none;
  width: 24%;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.kv-polaroid__moon {
  position: relative;
  display: block;
  width: var(--s, 12.3%);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 30%, #e8cfa6, #c49a5e 58%, #8a6238);
  box-shadow: 0 0 2px rgb(214 178 121 / 0.16);
  overflow: hidden;
}
.kv-polaroid__moon::after {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: 50%;
  background: #0a0a09;
  transform: translateX(var(--o));
}
/* 下巴：規格字樣 + 定位十字 + 曝光列 */
.kv-polaroid__meta {
  margin-top: 10px;
  font-family: var(--kiosk-font-mono);
  text-transform: uppercase;
  white-space: nowrap;
  line-height: 1.6;
}
.kv-polaroid__spec {
  display: flex;
  align-items: center;
  gap: 18px;
}
.kv-polaroid__reg {
  flex: none;
  width: 22px;
  aspect-ratio: 1;
  fill: none;
  stroke: #a77b43;
  stroke-width: 1;
  opacity: 0.6;
}
.kv-polaroid__spec-text {
  flex: 1;
  color: #d6b279;
  font-size: 17px;
  letter-spacing: 0.14em;
  text-align: center;
  opacity: 0.86;
  overflow: hidden;
}
.kv-polaroid__exposure {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-top: 10px;
  color: #a77b43;
  font-size: 13px;
  letter-spacing: 0.06em;
  opacity: 0.8;
}
.kv-polaroid__shot {
  flex: 1;
  overflow: hidden;
  text-align: right;
}
.kv-polaroid__arrow {
  flex: none;
  width: 34px;
  aspect-ratio: 26 / 18;
  background-image: linear-gradient(100deg, #e8cfa6 0%, #c49a5e 38%, #9c7140 78%, #8a6238 100%);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 18'%3E%3Cpath d='M0 6h16V0l10 9-10 9v-6H0z' fill='%23000'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 18'%3E%3Cpath d='M0 6h16V0l10 9-10 9v-6H0z' fill='%23000'/%3E%3C/svg%3E");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-size: contain;
  mask-size: contain;
  opacity: 0.9;
}

/* P06 預覽頁用的靜態版（設計師 2026-10-13：兩頁連貫；2026-10-14 從 film.css 搬進 DS）：放在 safe area 裡、600 寬、照片已顯影，不吐出不晃。
   整張相紙從 P05b 的位置 FLIP 飛過來（prototype / film 的 arrive）。 */
.kv-polaroid--review {
  position: relative;
  left: auto;
  bottom: auto;
  flex: none;
  width: 600px;
  padding: 25px 25px 34px;
  translate: 0 0;
  rotate: 0deg;
  animation: none;
  z-index: 2;
  transform-origin: 0 0;
}
.kv-polaroid--review .kv-polaroid__photo > img,
.kv-polaroid--review .kv-polaroid__photo > .kv-ph {
  animation: none;
  filter: none;
}
.kv-polaroid--review .kv-polaroid__head {
  margin-top: 10px;
  gap: 14px;
}
.kv-polaroid--review .kv-polaroid__meta {
  margin-top: 6px;
}
.kv-polaroid--review .kv-polaroid__spec {
  gap: 12px;
}
.kv-polaroid--review .kv-polaroid__reg {
  width: 16px;
}
.kv-polaroid--review .kv-polaroid__spec-text {
  font-size: 12.5px;
}
.kv-polaroid--review .kv-polaroid__exposure {
  margin-top: 6px;
  gap: 12px;
  font-size: 10px;
}
.kv-polaroid--review .kv-polaroid__arrow {
  width: 24px;
}
.kv-screen--arrive > .kv-topbar,
.kv-screen--arrive > .kv-transcript {
  animation: kv-fade-in 400ms ease-out 350ms both;
}
.kv-screen--arrive .kv-qr {
  animation: kv-qr-in 520ms cubic-bezier(0.33, 1, 0.68, 1) 250ms both;
}
.kv-screen--arrive .kv-photo {
  transform-origin: 0 0;
  z-index: 7;
  transition: transform 600ms cubic-bezier(0.33, 1, 0.68, 1);
}
.kv-screen--arrive .kv-photo::after {
  content: '';
  position: absolute;
  inset: -34px -34px -48px;
  background: linear-gradient(to right, #34312d 0%, #10100f 17%, #0a0a09 82%, #050505 100%);
  border-radius: 8px;
  z-index: -1;
  animation: kv-frame-out 500ms ease-out 150ms forwards;
}
@keyframes kv-fade-in {
  from {
    opacity: 0;
  }
}
@keyframes kv-qr-in {
  from {
    opacity: 0;
    translate: 80px 0;
  }
}
@keyframes kv-frame-out {
  to {
    opacity: 0;
  }
}
/* 07 思考 A04 · 同步脈動：Center 思考光點、Kebbi 眼睛浮動、LED 呼吸都走 --kiosk-dur-pulse 同一拍（.kv-face--sync） */
.kv-face--sync .kv-face__eye {
  animation: kv-face-float var(--kiosk-dur-pulse) ease-in-out infinite;
}
.kv-face--sync .kv-face__bar {
  animation: kv-bar-breathe var(--kiosk-dur-pulse) ease-in-out infinite;
}
@keyframes kv-bar-breathe {
  0%,
  100% {
    opacity: 0.5;
  }
  50% {
    opacity: 1;
  }
}
/* 08 聽不清楚 E01 · 歪頭：Kebbi 整對眼睛歪 10°（.kv-face--tilt），Center 問句微傾再回正（.kv-transcript--tilt） */
.kv-face--tilt .kv-face__eyes {
  rotate: 10deg;
  transition: rotate 500ms ease;
}
.kv-transcript--tilt {
  transform-origin: 0 50%;
  animation: kv-tilt-text 1400ms ease-in-out;
}
@keyframes kv-tilt-text {
  0%,
  100% {
    rotate: 0deg;
  }
  40% {
    rotate: 1.5deg;
  }
}
/* 09 太吵 E06 · 瞇眼抖（.kv-face--squint，1.2s 後移除）、對話框跟著抖（.kv-pill--shake） */
.kv-face--squint .kv-face__eye {
  height: 60px;
  animation: none;
}
.kv-face--squint .kv-face__eyes {
  animation: kv-shake 600ms ease-in-out;
}
.kv-face--squint .kv-face__bar {
  animation: kv-bar-grey 600ms steps(3) 2;
}
.kv-pill--shake {
  animation: kv-shake-s 600ms ease-in-out;
}
@keyframes kv-shake {
  0%,
  100% {
    translate: 0 0;
  }
  25% {
    translate: -24px 0;
  }
  50% {
    translate: 24px 0;
  }
  75% {
    translate: -12px 0;
  }
}
@keyframes kv-bar-grey {
  50% {
    opacity: 0.3;
  }
}
@keyframes kv-shake-s {
  0%,
  100% {
    translate: 0 0;
  }
  25% {
    translate: -6px 0;
  }
  50% {
    translate: 6px 0;
  }
  75% {
    translate: -3px 0;
  }
}
/* 10 Moving A01 · Kebbi 用 --kv-gx 看向前進方向；路線點換 class 時淡入（到站 Kebbi 回正 + 點頭由 JS） */
.kv-route__dot {
  transition: background 300ms ease;
}

/* ===================================================== v2.1 · 情境事件規格新增的元件
   milo 2026-10-01「情境事件規格」補進來的三個東西：收單橫幅、官方視覺標示、下一部上映小卡。 */

/* 官方視覺標示（巡邏移動播送）：左下「官方視覺」、右下「詳情資訊」小字。 */
.kv-stamp {
  position: absolute;
  left: var(--kiosk-margin);
  bottom: var(--kiosk-pill-bottom);
  padding: 8px 14px;
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: 6px;
  font: var(--kiosk-type-annot-sm);
  letter-spacing: 0.08em;
  color: var(--kiosk-text-muted-light);
  z-index: 6;
}
.kv-stamp--right {
  left: auto;
  right: var(--kiosk-margin);
  border: 0;
  padding: 8px 0;
}

/* 最近場次卡（C17）· 設計師 2026-10-06：問場次一律用這張。
   規則：最多 4 場；只列今天還沒開演的、近到遠；不足 4 場只放有的，不補空位；都開演完 → __empty 一句。
   不放海報（留位置給場次），片名在標題列、場次橫排平分。寬度跟著 safe area，高度 = safe area（316 / 388）。 */
.kv-showtimes {
  flex: 1;
  flex-direction: row;
  align-items: stretch;
  padding: 0;
  overflow: hidden;
}
.kv-showtimes__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: var(--kiosk-card-pad-y) var(--kiosk-card-pad-x);
}
.kv-showtimes__head {
  display: flex;
  align-items: baseline;
  justify-content: flex-start; /* 「最近場次」小字緊貼片名右邊，視線不用切到最右 */
  gap: var(--kiosk-space-5);
}
.kv-showtimes__film {
  font: var(--kiosk-type-card-value-md);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kv-showtimes__kind {
  font: var(--kiosk-type-card-label);
  color: var(--kiosk-text-secondary);
  white-space: nowrap;
}
.kv-showtimes__list {
  display: flex;
  gap: var(--kiosk-space-6);
}
.kv-showtimes__item {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}
.kv-showtimes__time {
  font: 800 64px/1 var(--kiosk-font-display);
  color: var(--kiosk-text-primary);
}
.kv-showtimes__meta {
  font: var(--kiosk-type-card-label);
  color: var(--kiosk-text-secondary);
  white-space: nowrap;
}
.kv-showtimes__empty {
  font: var(--kiosk-type-card-value-md);
  color: var(--kiosk-text-secondary);
}

/* 送客有人停下：QR 放大 */
.kv-screen--standby > .kv-qr--grow {
  transform: scale(1.18);
  transform-origin: 100% 0;
}

/* 魔法火光彩蛋（Micro Moments 11）· 複製自 Vyin 官網活動頁 C01 的氛圍層（hexed_html.zip / vyin-atmosphere.html，2026-10-06）。
   女主角比莉施法時的紅色火光：10 顆粒子從畫面下半往上飄、邊飄邊左右晃、兩端淡出。只動 transform 與 opacity。
   提到「比莉」（名字才算，「女主角」不算）或「魔法」時由 JS 把 .kv-embers 丟進目前畫面、約 8 秒後移除。vh 換成畫布像素（800 高）。 */
.kv-embers {
  position: absolute;
  inset: 0;
  z-index: 3; /* 在素材與遮罩上、文字與卡片下 */
  overflow: hidden;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 55%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 55%, transparent 100%);
  animation: kv-fade-in 600ms ease-out;
}
/* P05b 拍立得頁常駐一層火花在相紙後面（z 3 < 相紙 z 7），增加成就感；--loop 不會被 prototype 清場移除。設計師 2026-10-06 加。 */
.kv-embers--loop {
  animation: kv-fade-in 1200ms ease-out 600ms both;
}
.kv-embers--out {
  animation: kv-embers-out 800ms ease-out forwards;
}
/* v4.1（設計師 2026-10-20）：火光從 Side F 跑上來。Center 的火光從下緣外飄進來（進來時已經亮著），
   容器晚 1.2s 才出現（Side F 從中段起飛的那些大約那時飛出它的上緣）；--sparse 是 P06 預覽頁留的那幾顆；E10 還在傳時不慶祝 */
.kv-embers--from-below {
  animation: kv-fade-in 600ms ease-out 1200ms both; /* 設計師 2026-10-20：2.4s 太晚，改 1.2s；Side F 那邊有一部分火光從中段起飛，很快就到上緣 */
  -webkit-mask-image: none;
  mask-image: none;
}
.kv-embers--from-below > .kv-ember {
  bottom: -10%;
  animation-name: kv-ember-rise-in;
}
.kv-embers--sparse > .kv-ember {
  --op: 0.7;
}
.kv-screen--review2 > .kv-embers {
  z-index: 1; /* 在相紙與 QR 後面 */
}
.kv-screen:has(.kv-review2--fail) > .kv-embers {
  opacity: 0;
  transition: opacity 600ms ease-out;
}
@keyframes kv-ember-rise-in {
  0% {
    transform: translate3d(0, 0, 0);
    opacity: var(--op);
  }
  60% {
    opacity: var(--op);
  }
  100% {
    transform: translate3d(var(--drift), -640px, 0);
    opacity: 0;
  }
}

/* 12 提到「復仇者聯盟」或裡面的英雄名（設計師 2026-10-06 加）· 「集結」：不用任何漫威標誌、名稱或配色，只用我們的 UI 做英雄感——
   .kv-hud 疊在畫面上：兩圈震波從中心擴出去、四周粗邊框橘光呼吸兩次（設計師 2026-10-06：相機外框的四角拿掉、白色掃描線拿掉、圈與邊框加粗，只留紅）；素材本身 punch 一下（放大 1.05 → 1、對比飽和拉高再回）。
   顏色只用 Grow 5（橘紅）。約 3.2s 後淡出移除。Kebbi：鎖定 → 戰鬥臉 + 右手舉直 → 嘴角一撇收尾，燈紅白快閃。
   設計師 2026-10-06：第一版 3px 細線不合 DS；線寬改用相機 campaign 外框的 --kiosk-grow-border-camera（8px）、圓角 --kiosk-radius-camera（36px）、光暈 40px 同三級光暈。 */
.kv-hud {
  position: absolute;
  inset: 0;
  z-index: 7;
  pointer-events: none;
  --hud: var(--kiosk-grow-5);
  animation: kv-hud-fade 3200ms ease-in both;
}
@keyframes kv-hud-fade {
  0%,
  78% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
.kv-hud__edge {
  position: absolute;
  inset: 0;
  border-radius: var(--kiosk-radius-screen);
  animation: kv-hud-edge 1400ms ease-out 2 both;
}
@keyframes kv-hud-edge {
  0% {
    box-shadow:
      inset 0 0 0 0 transparent,
      inset 0 0 0 transparent;
  }
  18% {
    box-shadow:
      inset 0 0 0 12px var(--hud),
      inset 0 0 160px rgb(255 106 43 / 0.5);
  }
  100% {
    box-shadow:
      inset 0 0 0 0 transparent,
      inset 0 0 40px rgb(255 106 43 / 0.12);
  }
}
.kv-hud__ring {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 320px;
  height: 320px;
  translate: -50% -50%;
  border-radius: 50%;
  border: 14px solid var(--hud);
  box-shadow:
    0 0 40px var(--hud),
    inset 0 0 40px rgb(255 106 43 / 0.5);
  opacity: 0;
  animation: kv-hud-ring 1000ms cubic-bezier(0.2, 0.7, 0.2, 1) 180ms both;
}
.kv-hud__ring--2 {
  animation-duration: 1400ms;
  animation-delay: 520ms;
  border-width: var(--kiosk-grow-border-camera);
}
@keyframes kv-hud-ring {
  0% {
    scale: 0.15;
    opacity: 1;
  }
  100% {
    scale: 5;
    opacity: 0;
  }
}
.kv-screen--hero > .kv-art {
  animation: kv-hero-punch 700ms cubic-bezier(0.2, 0.8, 0.2, 1) 160ms;
}
@keyframes kv-hero-punch {
  0% {
    scale: 1;
    filter: none;
  }
  25% {
    scale: 1.05;
    filter: contrast(1.25) saturate(1.35) brightness(1.1);
  }
  100% {
    scale: 1;
    filter: none;
  }
}
@keyframes kv-embers-out {
  to {
    opacity: 0;
  }
}
.kv-ember {
  position: absolute;
  bottom: 12%;
  left: var(--x);
  width: var(--size);
  height: var(--size);
  border-radius: 50%;
  background: radial-gradient(circle, #ffd9a0 0%, #ff7a2a 18%, rgb(192 52 26 / 0.7) 55%, transparent 72%); /* 設計師 2026-10-06：中間的黃少一點，核心縮到 18% 就轉橙紅 */
  box-shadow: 0 0 calc(var(--size) * 1.5) rgb(255 122 42 / 0.8), 0 0 calc(var(--size) * 3) rgb(255 122 42 / 0.7), 0 0 calc(var(--size) * 6) rgb(192 52 26 / 0.5);
  mix-blend-mode: screen;
  opacity: 0;
  animation: kv-ember-rise var(--dur) linear var(--delay) infinite;
}
@keyframes kv-ember-rise {
  0% {
    transform: translate3d(0, 0, 0);
    opacity: 0;
  }
  12% {
    opacity: var(--op);
  }
  70% {
    opacity: var(--op);
  }
  100% {
    transform: translate3d(var(--drift), -560px, 0);
    opacity: 0;
  }
}

/* ===================================================== Position slots
   只在 .kv-screen 裡使用。把元件放到 1280×800 格線的固定位置。
   用版型（下一節）時不需要這些；混用也可以。 */
.kv-at-topbar {
  position: absolute;
  top: var(--kiosk-topbar-top);
  left: var(--kiosk-margin);
  right: var(--kiosk-margin);
  z-index: 6;
}
.kv-at-topbar--countdown {
  top: var(--kiosk-topbar-count-top);
}
.kv-at-route {
  position: absolute;
  top: var(--kiosk-route-top);
  right: var(--kiosk-margin);
  z-index: 6;
}
.kv-at-progress {
  position: absolute;
  top: 56px; /* derived · 頂列垂直中心 */
  left: 50%;
  transform: translateX(-50%);
  z-index: 6;
}
.kv-at-ai {
  position: absolute;
  top: var(--kiosk-ai-top);
  left: var(--kiosk-margin);
  width: var(--kiosk-ai-w);
  z-index: 2;
}
.kv-at-ai--cover {
  width: var(--kiosk-ai-w-cover);
}
.kv-at-caption {
  position: absolute;
  top: var(--kiosk-caption-top);
  left: var(--kiosk-margin);
  right: var(--kiosk-margin);
  z-index: 2;
}
/* 拍照畫面：不放 logo 與狀態 chip，字幕上移到頂列的位置 y 64（設計師 2026-09-30）。
   收音狀態由 Kebbi 光條與指令膠囊承接。 */
.kv-at-caption--camera {
  top: var(--kiosk-caption-top-camera);
}
.kv-at-status {
  position: absolute;
  top: var(--kiosk-status-top);
  left: var(--kiosk-margin);
  z-index: 2;
}
.kv-at-status--in-ai {
  top: var(--kiosk-ai-top);
  height: 72px;
}
.kv-at-safe {
  position: absolute;
  top: var(--kiosk-safe-top);
  left: var(--kiosk-margin);
  z-index: 2;
}
.kv-at-safe--one-line {
  top: var(--kiosk-safe-top-1line);
}
.kv-at-pill {
  position: absolute;
  left: var(--kiosk-pill-x);
  bottom: var(--kiosk-pill-bottom);
  z-index: 5;
}
.kv-at-pill--cta {
  left: var(--kiosk-margin);
}
.kv-at-cmd {
  position: absolute;
  left: var(--kiosk-cmd-x);
  bottom: var(--kiosk-pill-bottom);
  z-index: 5;
}
.kv-at-toast {
  position: absolute;
  left: 50%;
  bottom: var(--kiosk-toast-bottom);
  transform: translateX(-50%);
  z-index: 5;
}
.kv-at-hero {
  position: absolute;
  inset: 0;
  z-index: 2;
}
.kv-at-hero--left {
  left: var(--kiosk-margin);
  right: auto;
  width: var(--kiosk-ai-w-cover);
}
.kv-at-standby-qr {
  position: absolute;
  right: var(--kiosk-margin);
  top: var(--kiosk-standby-qr-top);
  z-index: 2;
}

/* ================================================================ Templates
   四種 Center 畫面骨架。直接子元件依 class 自動落到格線。
   · --dialog   頂列 + AI 區 + safe area + 對話框（P06–P08、A03–A05、E01–E06、W03–W04、X03–X04）
   · --media    滿版媒體 + 上下遮罩 + 字幕 + 媒體版頂列（P02–P05、A06）
   · --cover    滿版 key art + 左側遮罩 + 1100 寬 AI 字（P01、A02、A03；A01 加 --no-scrim 只留海報）
   · --standby  置中光暈 + hero 大標（W01、W02、X01、X02）
   狀態修飾：--one-line、--countdown、--no-pill、--camera、--cover-strong、--no-scrim、--scrim-tall。 */

/* --- dialog 的底（2026-10-14 定，取代 Neutral 950 純底）：
   放一個 .kv-art 進 --dialog，圖是首頁輪播「進對話那一刻」的那張（JS 規則：進對話就凍住、不再換；回首頁才繼續輪播），
   這裡自動壓暗 + 模糊 + 黑色遮罩。沒放 .kv-art 就是純底。 --- */
.kv-screen--dialog > .kv-art {
  inset: -80px; /* v4.0：比畫面大 80px，模糊後邊緣不會變亮（Handoff §1） */
}
.kv-screen--dialog > .kv-art > img {
  transform: none;
  filter: blur(var(--kiosk-dialog-blur)) brightness(var(--kiosk-dialog-dim)) saturate(var(--kiosk-dialog-saturate));
}
.kv-screen--dialog > .kv-art::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--kiosk-dialog-scrim);
}

/* --- 共用：頂列、對話框、指令膠囊、Toast、進度 --- */
.kv-screen--dialog > .kv-topbar,
.kv-screen--media > .kv-topbar,
.kv-screen--cover > .kv-topbar,
.kv-screen--standby > .kv-topbar {
  position: absolute;
  top: var(--kiosk-topbar-top);
  left: var(--kiosk-margin);
  right: var(--kiosk-margin);
  z-index: 6;
}
.kv-screen--dialog > .kv-pill,
.kv-screen--cover > .kv-pill,
.kv-screen--media > .kv-pill,
.kv-screen--standby > .kv-pill,
.kv-screen--dialog > .kv-actions,
.kv-screen--cover > .kv-actions,
.kv-screen--media > .kv-actions,
.kv-screen--standby > .kv-actions {
  position: absolute;
  left: var(--kiosk-pill-x);
  bottom: var(--kiosk-pill-bottom);
  z-index: 5;
}
.kv-screen--dialog > .kv-cmd,
.kv-screen--media > .kv-cmd {
  position: absolute;
  left: var(--kiosk-cmd-x);
  bottom: var(--kiosk-pill-bottom);
  z-index: 5;
}
.kv-screen--dialog > .kv-toast,
.kv-screen--media > .kv-toast,
.kv-screen--cover > .kv-toast,
.kv-screen--standby > .kv-toast {
  position: absolute;
  left: 50%;
  bottom: var(--kiosk-toast-bottom);
  transform: translateX(-50%);
  z-index: 5;
}
.kv-screen--dialog > .kv-progress {
  position: absolute;
  top: 56px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 6;
}
.kv-screen--dialog > .kv-dim,
.kv-screen--cover > .kv-dim,
.kv-screen--media > .kv-dim,
.kv-screen--standby > .kv-dim {
  z-index: 4;
}

/* --- dialog --- */
.kv-screen--dialog > .kv-transcript,
.kv-screen--cover > .kv-transcript {
  position: absolute;
  top: var(--kiosk-ai-top);
  left: var(--kiosk-margin);
  width: var(--kiosk-ai-w);
  z-index: 2;
}
.kv-screen--dialog > .kv-status {
  position: absolute;
  top: var(--kiosk-status-top);
  left: var(--kiosk-margin);
  z-index: 2;
}
.kv-screen--dialog > .kv-safe,
.kv-screen--dialog > .kv-chips,
.kv-screen--cover > .kv-chips {
  position: absolute;
  top: var(--kiosk-safe-top);
  left: var(--kiosk-margin);
  z-index: 2;
}
/* 純文字回答（v4.3，設計師 2026-10-30 定的完整對答 flow）：回答沒有卡片可放 → 內容區留空、AI 句放大一級（56/1.3，最多 3 行）、不回首頁；
   回答分 3–4 段講時一段換一段、chips 等最後一段說完才出（.is-chips）。有卡片的回答不加這個 class。 */
.kv-screen--dialog.is-solo > .kv-transcript {
  font: var(--kiosk-type-transcript-solo);
  max-height: 222px; /* 3 行 × 74 */
}
/* AI 只有 1 行：safe area 上移到 332、高 508 */
.kv-screen--one-line > .kv-transcript {
  max-height: 72px;
}
.kv-screen--one-line > .kv-safe {
  top: var(--kiosk-safe-top-1line);
  height: var(--kiosk-safe-h-1line);
}
/* 對話框隱藏：safe area 延伸到 y 1016（Review 頁、頂列倒數時）。
   有 .kv-actions 時 safe area 不延伸（底部那格被動作列用掉）。 */
.kv-screen--no-pill > .kv-safe,
.kv-screen--countdown > .kv-safe {
  height: var(--kiosk-safe-h-ext);
}
.kv-screen--no-pill:has(> .kv-actions) > .kv-safe,
.kv-screen--countdown:has(> .kv-actions) > .kv-safe {
  height: var(--kiosk-safe-h);
}
.kv-screen--one-line.kv-screen--no-pill > .kv-safe,
.kv-screen--one-line.kv-screen--countdown > .kv-safe {
  height: var(--kiosk-safe-h-1line-ext);
}
.kv-screen--no-pill > .kv-pill,
.kv-screen--countdown > .kv-pill {
  display: none;
}
/* 頂列有倒數：頂列另外上移 */
.kv-screen--countdown > .kv-topbar {
  top: var(--kiosk-topbar-count-top);
  height: var(--kiosk-topbar-count-h);
}

/* ================================================ 三行 AI、觸控模式、倒數疊加（2026-10-14 用影片定下來的三個修飾）
   --three-line：AI 區三行（216），safe area 下移到 368。只用在 --touch 或純文字回答。
   --touch：純觸控模式（A08 之後、連續 3 組退觸控後的待命版）。對話框拿掉、三個 chips 橫排住進底部那格
            （「底部那格永遠是你怎麼跟我說話」）、卡片與 QR 撐滿內容區（2 行 360、3 行 288；QR 碼 = 卡高 − 132，268 卡時正好 140）。
   --notice：A09 預告收單。頂列右側的日期時間換成倒數膠囊，其他都不動（跟 --countdown 不同：不動頂列位置、對話框、safe area）；
            倒數膠囊放在 .kv-topbar 最後一個子元素，頂列加 .kv-topbar--countdown 變 48 高。可疊在任何畫面。 */
.kv-screen--three-line > .kv-transcript {
  max-height: var(--kiosk-ai-h-3line);
}
.kv-screen--three-line > .kv-safe {
  top: var(--kiosk-safe-top-3line);
}
.kv-screen--touch > .kv-pill {
  display: none;
}
.kv-screen--touch > .kv-chips {
  top: auto;
  bottom: var(--kiosk-pill-bottom);
  left: var(--kiosk-pill-x);
  width: var(--kiosk-pill-w);
  height: var(--kiosk-slot-chips);
  flex-direction: row;
  justify-content: center;
  align-items: center;
}
.kv-screen--touch > .kv-safe {
  height: var(--kiosk-safe-h-touch);
  align-items: stretch;
}
.kv-screen--touch.kv-screen--three-line > .kv-safe {
  height: var(--kiosk-safe-h-touch-3line);
}
.kv-screen--touch > .kv-safe > .kv-card {
  height: auto;
}
.kv-screen--touch > .kv-safe > .kv-qr {
  height: auto;
  width: var(--kiosk-safe-h-touch);
  --kiosk-qr-code: calc(var(--kiosk-safe-h-touch) - 132px);
}
.kv-screen--touch.kv-screen--three-line > .kv-safe > .kv-qr {
  width: var(--kiosk-safe-h-touch-3line);
  --kiosk-qr-code: calc(var(--kiosk-safe-h-touch-3line) - 132px);
}
/* chips 按下態（互動規則：填色升一階 + 縮 97%、120ms） */
.kv-chip {
  transition:
    transform var(--kiosk-dur-press) var(--kiosk-ease),
    background-color var(--kiosk-dur-press) var(--kiosk-ease);
}
.kv-chip:active,
.kv-chip--down {
  background: var(--kiosk-border);
  transform: scale(0.97);
}
.kv-screen--notice > .kv-topbar > .kv-topbar__meta {
  display: none;
}
/* E05 在預告上：說明用字幕位，「重新連線中」小字列放在字幕下方（跟對話畫面的 .kv-status 同 y） */
.kv-screen--media > .kv-status {
  position: absolute;
  top: var(--kiosk-status-top);
  left: var(--kiosk-margin);
  z-index: 3;
}

/* 思考態放在 AI 區本身（回答會出現的位置）：A04 */
.kv-screen--dialog > .kv-status--in-ai {
  top: var(--kiosk-ai-top);
  height: 72px;
}

/* --- media --- */
.kv-screen--media::before,
.kv-screen--media::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  height: var(--kiosk-scrim-h);
  pointer-events: none;
  z-index: 1;
}
.kv-screen--media::before {
  top: 0;
  background: var(--kiosk-scrim-top);
}
.kv-screen--scrim-tall::before {
  height: var(--kiosk-scrim-h-tall); /* 預告：上遮罩 360 */
}
.kv-screen--media > .kv-media-bar {
  position: absolute;
  left: var(--kiosk-margin);
  bottom: var(--kiosk-media-bar-bottom);
  z-index: 2;
}
/* 提示膠囊移到右上角，不擋影片內容（設計師 2026-10-01）。v2.9：改為暫停+停止按鈕列。 */
.kv-screen--media > .kv-media-bar__hint {
  position: absolute;
  top: var(--kiosk-topbar-top);
  right: var(--kiosk-margin);
  z-index: 2;
}
.kv-screen--media > .kv-media-controls {
  position: absolute;
  bottom: var(--kiosk-media-bar-bottom);
  right: var(--kiosk-margin);
  display: flex;
  gap: 16px;
  z-index: 2;
}
.kv-screen--media > .kv-media-progress {
  position: absolute;
  left: var(--kiosk-margin);
  right: var(--kiosk-margin);
  bottom: var(--kiosk-media-progress-bottom);
  z-index: 2;
}
.kv-screen--media::after {
  bottom: 0;
  background: var(--kiosk-scrim-bottom);
}
.kv-screen--media > .kv-transcript {
  position: absolute;
  top: var(--kiosk-caption-top);
  left: var(--kiosk-margin);
  right: var(--kiosk-margin);
  font: var(--kiosk-type-caption);
  max-height: none;
  text-shadow: var(--kiosk-text-shadow-media);
  z-index: 2;
}
/* Focus 層級（拍照）：頂列隱藏、字幕上移到 y 64、只留任務內容。
   收音狀態由 Kebbi 光條承接；光條不可用時用 .kv-mic--dot 放右上角（fallback）。 */
.kv-screen--camera > .kv-topbar {
  display: none;
}
.kv-screen--camera > .kv-transcript {
  top: var(--kiosk-caption-top-camera);
}
.kv-screen--camera > .kv-hint,
.kv-screen--dialog > .kv-hint,
.kv-screen--cover > .kv-hint {
  position: absolute;
  left: 50%;
  bottom: var(--kiosk-toast-bottom);
  transform: translateX(-50%);
  z-index: 5;
}
/* 有動作列或 CTA 按鈕時，提示移到動作列上方 */
.kv-screen--dialog > .kv-actions ~ .kv-hint,
.kv-screen--cover > .kv-actions ~ .kv-hint {
  bottom: 156px; /* pill-bottom 44 + pill-h 96 + gap 16 */
}
.kv-screen--camera > .kv-mic--dot {
  position: absolute;
  top: var(--kiosk-topbar-top);
  right: var(--kiosk-margin);
  z-index: 6;
}

/* 媒體與 standby、cover 上的頂列：logo 加陰影、收音狀態包膠囊 */
.kv-screen--media .kv-logo,
.kv-screen--standby .kv-logo,
.kv-screen--cover .kv-logo {
  text-shadow: var(--kiosk-text-shadow-logo);
}
/* 亮色底圖：日期時間切深色（預設白色；加 .kv-screen--bg-light 切換） */
.kv-screen--bg-light .kv-date,
.kv-screen--bg-light .kv-clock {
  color: rgba(0, 0, 0, 0.6);
}
.kv-screen--media .kv-mic,
.kv-screen--standby .kv-mic,
.kv-screen--cover .kv-mic {
  background: var(--kiosk-overlay-media);
  border-radius: var(--kiosk-radius-pill);
  padding: 8px 16px 8px 12px;
}

/* --- cover --- */
.kv-screen--cover::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--kiosk-scrim-cover);
  pointer-events: none;
  z-index: 1;
}
.kv-screen--cover-strong::before {
  background: var(--kiosk-scrim-cover-strong);
}
/* Photo Idle（P01）：海報滿版 + 左遮罩，獨立 CTA 按鈕 + 小提示 */
.kv-screen--cover > .kv-btn {
  position: absolute;
  bottom: var(--kiosk-pill-bottom);
  left: var(--kiosk-margin);
  z-index: 5;
}
.kv-screen--cover > .kv-cta-hint {
  position: absolute;
  bottom: var(--kiosk-cta-hint-bottom);
  left: var(--kiosk-margin);
  z-index: 5;
  transition: opacity var(--kiosk-dur-fade) var(--kiosk-ease);
}
/* v4.1 喚醒中（P01a）。2026-10-21 改：指令已經收到、喚醒中按什麼都沒用，所以**畫面上不放任何按鈕**（CTA 與提示小字收掉）。
   改用對話框「已送出」態 .kv-pill--sent 回饋：外觀同聆聽（Grow 環 + 光暈 + 背景壓暗），裡面是他剛剛的指令（點 CTA 就是按鈕字、
   說話就是他說的話），但**沒有游標、沒有波形**（不是在聽），右側換成「正在啟動」；頂列收音膠囊換「啟動中」（這段語音不收）。
   機器人不轉身；就緒直接進下一步，不再說邀請句。 */
.kv-screen--cover > .kv-btn,
.kv-screen--cover > .kv-cta-hint {
  transition: opacity var(--kiosk-dur-fade) var(--kiosk-ease);
}
.kv-screen--cover.is-starting > .kv-btn,
.kv-screen--cover.is-starting > .kv-cta-hint {
  opacity: 0;
  visibility: hidden;
}
/* 凱比那句「來了，等我一下」是回應，不壓在暗幕下 */
.kv-screen--cover.is-starting > .kv-transcript {
  z-index: 5;
}
/* 海報自己有字時不壓我們的字，也不壓遮罩（Moving A01）：只留頂列與路線膠囊 */
.kv-screen--no-scrim::before {
  display: none;
}
.kv-screen--cover > .kv-transcript {
  width: var(--kiosk-ai-w-cover);
}
.kv-screen--cover > .kv-route {
  position: absolute;
  top: var(--kiosk-route-top);
  right: var(--kiosk-margin);
  z-index: 6;
}

/* --- standby --- */
/* 去字 key art 底（W01–W02、X01–X03）· 設計師 2026-10-05 定案，取代原本 Welcome 的置中紫色光暈（glow 修飾已移除）。
   圖以 --kiosk-keyart-pos 為焦點縮放、壓到 44%，::before 再疊一層置中暗角，置中大標與左欄字才可讀。
   四個值都在 tokens.css，改那裡就好；沒放 .kv-art 的 standby 畫面不會有暗角（:has()，Chromium 105+）。 */
.kv-screen--standby > .kv-art > img {
  object-position: var(--kiosk-keyart-pos);
  transform-origin: var(--kiosk-keyart-pos);
  transform: scale(var(--kiosk-keyart-scale));
  opacity: var(--kiosk-keyart-opacity);
}
.kv-screen--standby:has(> .kv-art)::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--kiosk-vignette-bg);
  opacity: var(--kiosk-keyart-vignette);
  pointer-events: none;
  z-index: 1;
}
.kv-screen--standby > .kv-hero {
  position: absolute;
  inset: 0;
  z-index: 2;
}
/* cover 版型上的左欄 hero（M03 回崗位的大字；原 E09）：同 standby 的 hero--left 寬，垂直置中 */
.kv-screen--cover > .kv-hero--left {
  position: absolute;
  left: var(--kiosk-margin);
  top: 0;
  bottom: 0;
  width: var(--kiosk-ai-w-cover);
  justify-content: center;
  z-index: 2;
}
.kv-screen--standby > .kv-hero--left {
  left: var(--kiosk-margin);
  right: auto;
  width: var(--kiosk-ai-w-cover);
}
.kv-screen--standby > .kv-qr {
  position: absolute;
  right: var(--kiosk-margin);
  top: var(--kiosk-standby-qr-top);
  z-index: 2;
}
.kv-screen--standby > .kv-safe {
  position: absolute;
  top: var(--kiosk-safe-top);
  left: var(--kiosk-margin);
  z-index: 2;
}

/* =========================================================== Grid guides
   開發用格線疊層。加 .kv-guides 到 .kv-screen 才顯示。 */
.kv-guide {
  display: none;
  position: absolute;
  z-index: 50;
  pointer-events: none;
  border: 3px dashed;
}
.kv-guide__tag {
  position: absolute;
  right: 12px;
  top: 10px;
  font: 600 22px/1 var(--kiosk-font-mono);
  white-space: nowrap;
}
.kv-guides .kv-guide {
  display: block;
}
.kv-guide--topbar {
  top: var(--kiosk-topbar-top);
  left: var(--kiosk-margin);
  width: var(--kiosk-ai-w);
  height: var(--kiosk-topbar-h);
  border-color: rgba(163, 163, 163, 1);
  background: rgba(163, 163, 163, 0.07);
  color: rgba(163, 163, 163, 1);
}
.kv-guide--ai {
  top: var(--kiosk-ai-top);
  left: var(--kiosk-margin);
  width: var(--kiosk-ai-w);
  height: var(--kiosk-ai-h);
  border-color: rgba(34, 211, 238, 1);
  background: rgba(34, 211, 238, 0.07);
  color: rgba(34, 211, 238, 1);
}
.kv-guide--safe {
  top: var(--kiosk-safe-top);
  left: var(--kiosk-margin);
  width: var(--kiosk-ai-w);
  height: var(--kiosk-safe-h);
  border-color: rgba(236, 72, 153, 1);
  background: rgba(236, 72, 153, 0.07);
  color: rgba(236, 72, 153, 1);
}
.kv-guide--safe-one-line {
  top: var(--kiosk-safe-top-1line);
  height: var(--kiosk-safe-h-1line);
}
.kv-guide--safe-extended {
  height: var(--kiosk-safe-h-ext);
}
.kv-guide--pill {
  left: var(--kiosk-pill-x);
  top: calc(var(--kiosk-center-h) - var(--kiosk-pill-bottom) - var(--kiosk-pill-h-listen));
  width: var(--kiosk-pill-w);
  height: var(--kiosk-pill-h-listen);
  border-color: rgba(250, 204, 21, 1);
  background: rgba(250, 204, 21, 0.07);
  color: rgba(250, 204, 21, 1);
}

/* ==========================================================================
   Prototype 狀態機（data-chrome / data-mic）
   工程師在 .kv-screen 上設 data-chrome 和 data-mic，CSS 自動控制顯示。
   切換用 200ms opacity transition。
   ========================================================================== */

/* --- transition 基底 --- */
.kv-screen .kv-topbar,
.kv-screen .kv-topbar__meta,
.kv-screen .kv-mic,
.kv-screen .kv-pill,
.kv-screen .kv-actions,
.kv-screen > .kv-btn,
.kv-screen > .kv-cta-hint {
  transition: opacity var(--kiosk-dur-chrome) var(--kiosk-ease);
}

/* --- data-chrome="ambient"：隱藏日期時間、對話框、CTA --- */
.kv-screen[data-chrome="ambient"] .kv-topbar__meta,
.kv-screen[data-chrome="ambient"] .kv-pill,
.kv-screen[data-chrome="ambient"] .kv-actions,
.kv-screen[data-chrome="ambient"] > .kv-btn,
.kv-screen[data-chrome="ambient"] > .kv-cta-hint {
  opacity: 0;
  pointer-events: none;
}

/* --- data-chrome="focus"：隱藏整個頂列（logo + mic + 時間）、對話框、CTA --- */
.kv-screen[data-chrome="focus"] .kv-topbar,
.kv-screen[data-chrome="focus"] .kv-pill,
.kv-screen[data-chrome="focus"] .kv-actions,
.kv-screen[data-chrome="focus"] > .kv-btn,
.kv-screen[data-chrome="focus"] > .kv-cta-hint {
  opacity: 0;
  pointer-events: none;
}

/* --- data-mic：收音狀態驅動 ---
   設定 data-mic 時覆寫 .kv-mic 的光點顏色、標籤文字、光暈。
   實際 class（kv-mic--full / --off / --command / --dot）仍可用於靜態展示，
   data-mic 在 Prototype 階段優先。 */

.kv-screen[data-mic="full"] .kv-mic__dot {
  background: var(--kiosk-grow);
  box-shadow: var(--kiosk-halo-full);
}
.kv-screen[data-mic="off"] .kv-mic__dot {
  background: var(--kiosk-text-disabled);
  box-shadow: none;
}
.kv-screen[data-mic="cmd"] .kv-mic__dot {
  background: var(--kiosk-warning);
  box-shadow: var(--kiosk-halo-command);
}
/* data-mic="dot"：只顯示光點，隱藏標籤（FOCUS fallback） */
.kv-screen[data-mic="dot"] .kv-mic__label {
  display: none;
}


/* ============================================================ v4.0 · Photo v2 新元件（2026-10-19 從 prototype-photo.css 搬入）
   選版型卡、移動中 / 到位、拍好了（review2）、限動框（story）與吐出版。值照設計師的 Photo Flow Handoff（2026-10-16）與
   10/16–10/19 的裁定；記錄在 external/docs/2026-vyin-robot-lobby-photo-v2.md。 */

/* --- 選版型（Handoff P-PICK）：放在 .kv-safe，兩張寬卡並排 gap 16、撐滿高度；卡內左限動框預覽、中標題、右下圓鈕 --- */
.kv-pick {
  display: flex;
  gap: var(--kiosk-card-gap);
  width: var(--kiosk-ai-w);
  height: var(--kiosk-safe-h);
}
/* 選版型卡的照片格是黑底、不放照片（設計師 2026-10-21：使用者才看得清楚版型本身） */
.kv-pick-card .kv-story__slot {
  background: #000;
}
.kv-pick-card .kv-story__slot > img {
  visibility: hidden;
}
.kv-pick-card {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 36px;
  padding: 36px 40px;
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-glass-info);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
  cursor: pointer;
  transition:
    transform var(--kiosk-dur-press) var(--kiosk-ease),
    background var(--kiosk-dur-press) var(--kiosk-ease),
    box-shadow var(--kiosk-dur-press) var(--kiosk-ease),
    opacity var(--kiosk-dur-press) var(--kiosk-ease);
}
.kv-pick-card.is-pressed {
  transform: scale(0.97);
  background: rgba(255, 255, 255, 0.12);
  box-shadow: inset 0 0 0 2px var(--kiosk-line-pressed), var(--kiosk-shadow-card);
}
.kv-pick-card.is-dimmed {
  opacity: 0.45;
}
.kv-pick-card__preview {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 236px;
  height: 100%;
}
.kv-pick-card__preview > .kv-story {
  --story-w: 196px; /* 348 高，塞得進 360 高的預覽欄 */
  pointer-events: none;
}
.kv-pick-card--single .kv-pick-card__preview > .kv-story {
  transform: rotate(-3deg);
}
.kv-pick-card--strip .kv-pick-card__preview > .kv-story {
  transform: rotate(3deg);
}
.kv-pick-card__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.kv-pick-card__title {
  font: 700 40px/1.25 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
}
.kv-pick-card__desc {
  font: 400 20px/1.4 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
}

/* --- 移動中 / 到位（Handoff P-MOVE、P-ARRIVE）：跟選版型同一個 screen，.is-moving / .is-arrived 時藏 AI 句與卡片、只換大字；背景不換 --- */
.kv-move,
.kv-move__hint {
  display: none;
}
.kv-screen.is-moving > .kv-transcript,
.kv-screen.is-moving > .kv-pick,
.kv-screen.is-arrived > .kv-transcript,
.kv-screen.is-arrived > .kv-pick {
  display: none;
}
/* 帶路 / 到位不期待觀眾操作（設計師 2026-11-09，對齊實機）：不放回首頁（語音 .kv-home、觸控 .kv-tnav），也沒有取消 */
.kv-screen.is-moving > .kv-home,
.kv-screen.is-arrived > .kv-home,
.kv-screen.is-moving > .kv-tnav,
.kv-screen.is-arrived > .kv-tnav {
  display: none;
}
.kv-screen.is-moving > .kv-move--go,
.kv-screen.is-moving > .kv-move__hint,
.kv-screen.is-arrived > .kv-move--arrive {
  display: flex;
}
.kv-move {
  position: absolute;
  inset: 0;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  text-align: center;
  z-index: 2;
}
.kv-move__arrows {
  display: flex;
  gap: 8px;
  font: 800 120px/1 var(--kiosk-font-display);
  background: var(--kiosk-grow);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  margin-bottom: -8px;
}
.kv-move__arrows > span {
  display: inline-block;
  animation: kv-move-arrow 1.2s ease-in-out infinite;
}
.kv-move__arrows > span:nth-child(2) {
  animation-delay: 0.2s;
}
.kv-move__arrows > span:nth-child(3) {
  animation-delay: 0.4s;
}
/* v4.3 ② E13 擋路：帶路畫面不換，箭頭停住變淡（不再往前），字由 js 換（.kv-move__sub / .kv-move__hint） */
.kv-screen.is-blocked > .kv-move--go > .kv-move__arrows > span,
.kv-side-move.is-blocked .kv-side-move__chev {
  animation: none; /* 不能只 pause：暫停中的 keyframe 會蓋掉這裡的 opacity */
  opacity: 0.3;
}
@keyframes kv-move-arrow {
  0%,
  100% {
    opacity: 0.25;
  }
  40% {
    opacity: 1;
  }
}
.kv-move__title {
  font: 900 132px/1.1 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
  letter-spacing: 0.02em;
}
.kv-move--arrive .kv-move__title {
  font-size: 160px;
}
.kv-move__sub {
  font: 400 30px/1.4 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
}
.kv-move__hint {
  position: absolute;
  left: 50%;
  bottom: var(--kiosk-toast-bottom);
  transform: translateX(-50%);
  padding: 16px 32px;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-info);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
  font: 400 20px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
  white-space: nowrap;
  z-index: 3;
}
.kv-screen.is-moving > .kv-move--go > *,
.kv-screen.is-arrived > .kv-move--arrive > * {
  animation: kv-rise-in 0.5s cubic-bezier(0.33, 1, 0.68, 1) both;
}
.kv-screen.is-moving > .kv-move--go > :nth-child(2) {
  animation-delay: 0.08s;
}
.kv-screen.is-moving > .kv-move--go > :nth-child(3) {
  animation-delay: 0.16s;
}
@keyframes kv-rise-in {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* --- 限動框（story）：最終輸出的樣子，三層（設計師 2026-10-19 正式素材「2.照片框」）：
   背景 .kv-story__bg（整張海報）→ 照片格 .kv-story__slot（920×690，圓角 80）→ 照片框 .kv-story__frame（框線 + 角色 + logo，其餘透明）。
   格的位置用框的百分比；寬由 --story-w 決定、9:16。選版型卡、P05b 吐出、P06 review、E10 共用；素材換尺寸只改 --sx/--sy/--sw/--sh --- */
.kv-story {
  --story-w: 416px;
  position: relative;
  flex: none;
  width: var(--story-w);
  aspect-ratio: 9 / 16;
  border-radius: calc(var(--story-w) * 0.03);
  overflow: hidden;
  background: var(--kiosk-surface-base);
  box-shadow: var(--kiosk-shadow-photo), 0 0 0 1px rgba(255, 255, 255, 0.08) inset;
  transform-origin: 0 0;
}
.kv-story__bg,
.kv-story__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.kv-story__bg {
  z-index: 0;
}
.kv-story__frame {
  z-index: 2;
}
/* v4.1 動態照片框（連拍才有）：透明影片疊在照片上，跟靜態框同位置；.is-live 時換成它、照片格播「短影片」。
   P05b 拍立得、P06 預覽都只放動態版（v4.2 設計師 2026-10-28；原本 P06 會在快門點定格 1.5 秒，拿掉了）。
   prototype 沒有真的錄影，照片格用慢慢推近的劇照代表「影片」；實機是 App 本機剛錄的片段（不用等後端合成）。 */
/* 影片真的在播（.kv-vid-on，js/frames.js 聽 playing 事件）才換掉靜態框，不然維持靜態框 */
.kv-story > video.kv-story__frame--video {
  object-fit: fill;
  opacity: 0;
}
.kv-story.is-live.kv-vid-on > video.kv-story__frame--video {
  opacity: 1;
}
.kv-story.is-live.kv-vid-on > img.kv-story__frame {
  visibility: hidden;
}
.kv-story.is-live .kv-story__slot > img {
  animation: kv-clip calc(5s / var(--kv-clip-speed, 1)) linear infinite;
}
/* 快門點停住：照片格的「影片」暫停在那一格（實機就是照片），框的影片 JS 暫停 */
/* 舊照片牆（v4.3 退場，只剩 transitions-explore.html）的照片是死圖：框會動、照片不動 */
.kv-side-photos .kv-story.is-live .kv-story__slot > img {
  animation: none;
}
.kv-story.is-live.is-hold .kv-story__slot > img {
  animation-play-state: paused;
}
@keyframes kv-clip {
  from {
    transform: scale(1.08) translateX(-1.5%);
  }
  to {
    transform: scale(1) translateX(1.5%);
  }
}
.kv-story__slot {
  position: absolute;
  left: calc(var(--sx) * 1%);
  top: calc(var(--sy) * 1%);
  width: calc(var(--sw) * 1%);
  height: calc(var(--sh) * 1%);
  overflow: hidden;
  border-radius: calc(var(--story-w) * 0.0741); /* 照片格圓角 80 / 1080 */
  background: var(--kiosk-surface-raised);
  z-index: 1;
}
.kv-story__slot > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* 照片格的座標（設計師「重要_尺寸標註說明」：左右邊 80、單張上 590 / 下 640；連拍上 140、格距 20、下 380；% of 1080×1920） */
.kv-story--single .kv-story__slot {
  --sx: 7.407;
  --sy: 30.729;
  --sw: 85.185;
  --sh: 35.938;
}
.kv-story--strip .kv-story__slot:nth-of-type(1) {
  --sx: 7.407;
  --sy: 7.292;
  --sw: 85.185;
  --sh: 35.938;
}
.kv-story--strip .kv-story__slot:nth-of-type(2) {
  --sx: 7.407;
  --sy: 44.271;
  --sw: 85.185;
  --sh: 35.938;
}
/* P05b 吐出版：置底吐出（照 .kv-polaroid 的節奏）+ 照片顯影。360 寬 → 640 高，停在離底 48。
   v4.1（設計師 2026-10-20：顯影時拍立得跑慢一點）：吐出 900 → 1400ms、顯影 2400 → 3400ms（延遲 600 → 800） */
.kv-story.kv-story--pop {
  --story-w: 360px;
  position: absolute;
  left: 50%;
  bottom: 0;
  translate: -50% 120%;
  rotate: -2deg;
  animation: kv-story-up 1400ms cubic-bezier(0.33, 1, 0.68, 1) forwards;
  z-index: 7;
}
@keyframes kv-story-up {
  to {
    translate: -50% -48px;
  }
}
.kv-story--pop .kv-story__slot > img {
  filter: brightness(0.04) saturate(0) contrast(1.4);
  animation: kv-develop 3400ms ease-out 800ms forwards;
}
/* v4.2（設計師 2026-10-28）：吐出來的是動態版——顯影跟「短影片」一起跑；從快門那一格開始（-3s = 短影片第 3 秒） */
.kv-story--pop.is-live .kv-story__slot > img {
  animation:
    kv-develop 3400ms ease-out 800ms forwards,
    kv-clip calc(5s / var(--kv-clip-speed, 1)) linear calc(-3s / var(--kv-clip-speed, 1)) infinite;
}

/* --- 拍好了（Handoff P-REVIEW）：左欄 AI 文字（left 56 / top 100 / 寬 440）+ 左下法務小字；右側限動框 + QR 卡疊放，整組上下置中 --- */
.kv-screen--review2 > .kv-transcript {
  top: 100px;
  left: 56px;
  width: 440px;
}
.kv-screen--review2 > .kv-hint.kv-hint--legal {
  position: absolute;
  top: auto;
  left: 56px;
  right: auto;
  bottom: 48px;
  width: 440px;
  margin: 0;
  padding: 0;
  transform: none;
  text-align: left;
  white-space: normal;
  font: 400 18px/1.5 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
  text-shadow: none;
  z-index: 2;
}
.kv-review2 {
  position: absolute;
  left: 560px;
  top: 0;
  bottom: 0;
  width: 656px;
  display: flex;
  align-items: center;
  z-index: 2;
  pointer-events: none;
}
.kv-review2 > .kv-story {
  --story-w: 350px; /* 622 高 */
  z-index: 2;
  transform: rotate(-4deg);
  transition: transform 700ms cubic-bezier(0.33, 1, 0.68, 1);
}
.kv-review2--strip > .kv-story {
  transform: rotate(4deg);
}
/* QR 卡疊在相片前面（才掃得到）、跟相片一起上下置中、反向傾斜 ±3°；白板 240、圓角 22、內距 18 */
.kv-review2__qr {
  position: absolute;
  left: 300px;
  top: 50%;
  z-index: 3;
  transform: translateY(-50%) rotate(3deg);
}
.kv-review2--strip > .kv-review2__qr {
  transform: translateY(-50%) rotate(-3deg);
}
.kv-review2__qr-in {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 20px 20px 16px;
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-glass-info);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info), var(--kiosk-shadow-photo);
}
.kv-screen.is-arrive .kv-review2__qr-in {
  animation: kv-rise-in 0.5s 0.35s cubic-bezier(0.33, 1, 0.68, 1) both;
}
.kv-review2__qr-in .kv-qr__plate {
  padding: 18px;
  border-radius: 22px;
}
.kv-review2__qr-in .kv-qr__code {
  --kiosk-qr-code: 204px;
}
.kv-review2__title {
  font: 700 22px/1.3 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
}

/* --- E10 照片還在傳 / 上傳失敗（v4.0 review2 版，設計師 2026-10-19 第三版）：限動框微傾 +2°（跟 P06 反向）、縮到 86%、靠右跟頂列日期時間對齊（右邊線 1216），
   QR 卡不出現；照片格換成 loading（.kv-status：光點 + 「上傳中 · 第 n 次」，不顯示失敗原因）；底部動作列「我再試一次」；AI「照片還在傳，再等我一下。」
   傳成功 → 拿掉 .kv-review2--fail：框滑回崗位、放大、傾斜 ±4°（transform transition 700ms），QR 卡進場（kv-rise-in），照片顯影 --- */
.kv-review2--fail > .kv-story {
  /* 350 × 0.86 = 301 寬；右邊線貼 1216（= 560 + 656）：left 915 → 往右 355；高 535 → 往下 43 維持垂直置中 */
  transform: translate(355px, 43px) scale(0.86) rotate(2deg); /* 設計師 2026-10-19：傾斜一點點、跟 P06 的 -4° 反向，轉場時會翻過去 */
}
.kv-review2--fail > .kv-review2__qr {
  display: none;
}
.kv-story__slot > .kv-status {
  display: none;
}
.kv-review2--fail .kv-story__slot > img {
  visibility: hidden;
}
.kv-review2--fail .kv-story__slot > .kv-status {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(var(--story-w) * 0.04);
  height: auto;
  padding: 0;
}
.kv-review2--fail .kv-story__slot .kv-status__label {
  font: 600 calc(var(--story-w) * 0.052) / 1.3 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
  white-space: normal;
  text-align: center;
}
/* review2 底部有動作列時，法務小字讓位 */
.kv-screen--review2.is-actions > .kv-hint.kv-hint--legal {
  opacity: 0;
}
/* 觸控模式的 P06（TR / TR2）：底部那格是導覽（← 回首頁 + 再拍一次），法務小字往上讓到導覽上方（設計師 2026-10-29：疊在一起了） */
.kv-screen--touch.kv-screen--review2 > .kv-hint.kv-hint--legal {
  bottom: calc(var(--kiosk-pill-bottom) + var(--kiosk-slot-chips) + 20px);
}


/* ============================================================ v4.2 · 點擊開始（P01 待命 → P01a 喚醒中 → P01b 開場，2026-10-23）
   現場太吵，待命不收音：Center 一整片就是按鈕，點了才 session.start、才開始收音。
   版面照 Claude Design 設計稿（記錄見 docs/2026-vyin-robot-lobby-photo-v2.md v4.2 段），元件與數值套回 DS。
   三張畫面共用同一個 .kv-screen--start，用 is-idle / is-cast / is-wait / is-open 切狀態；轉場引擎在 js/start.js。
   火光（.kv-fire）、骨架（.kv-skel）、對話框過渡態（.is-settling）只動 transform / opacity。 */

/* --- 畫面：待命與開場共用同一個 .kv-screen，用 is-idle / is-cast / is-wait / is-open 切狀態 --- */
.kv-screen--start::before {
  background: var(--kiosk-scrim-start);
}
.kv-screen--start > .kv-art {
  transition: filter var(--kiosk-dur-cast) var(--kiosk-ease), transform var(--kiosk-dur-cast) var(--kiosk-ease);
}
/* 點了之後：背景模糊壓暗（同 v3.0 Mode 轉場 B 的做法），一路用到 P01b */
.kv-screen--start:not(.is-idle) > .kv-art {
  filter: blur(28px) brightness(0.4) saturate(120%);
  transform: scale(1.06);
}
.kv-screen--start::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(10, 10, 10, 0.35);
  opacity: 0;
  transition: opacity var(--kiosk-dur-cast) var(--kiosk-ease);
  pointer-events: none;
  z-index: 1;
}
.kv-screen--start:not(.is-idle)::after {
  opacity: 1;
}

/* 例外（設計師 2026-10-23 同意）：P01 整片螢幕就是按鈕，Grow 環包整個畫面。只在 P01 用。 */
.kv-start-frame {
  position: absolute;
  inset: 20px;
  border-radius: 40px;
  z-index: 2;
  pointer-events: none;
  box-shadow: inset 0 0 40px rgba(31, 111, 224, 0.4);
  animation: kv-start-breathe 3.2s ease-in-out infinite;
  transition: opacity var(--kiosk-dur-fade) var(--kiosk-ease);
}
.kv-start-frame::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: var(--kiosk-grow-ring);
  background: var(--kiosk-grow);
  -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);
}
@keyframes kv-start-breathe {
  0%, 100% { box-shadow: inset 0 0 40px rgba(31, 111, 224, 0.4); }
  50% { box-shadow: inset 0 0 72px rgba(31, 111, 224, 0.6); }
}
.kv-screen--start:not(.is-idle) > .kv-start-frame {
  opacity: 0;
  animation: none;
}

/* P01 歡迎：eyebrow 用 DS .kv-eyebrow（設計稿的等寬字套回 Noto）；大標一行置中。
   v4.3 設計師 2026-10-30：**待命不放大標**，整張只留 key art + 底部「點擊任一處，開啟魔法對話」——markup 留著（每支 film / screens / DS 都有），這裡整個藏掉，要回來刪這條就好 */
.kv-screen--start > .kv-welcome {
  display: none;
}
.kv-welcome {
  position: absolute;
  left: 0;
  right: 0;
  top: 76px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
  text-align: center;
  z-index: 2;
  transition: opacity var(--kiosk-dur-fade) var(--kiosk-ease), transform var(--kiosk-dur-fade) var(--kiosk-ease);
}
.kv-welcome__title {
  font: var(--kiosk-type-welcome);
  letter-spacing: 0.02em;
  white-space: nowrap;
  color: var(--kiosk-text-primary);
  text-shadow: var(--kiosk-text-shadow-media);
}
.kv-start-hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 60px;
  text-align: center;
  font: var(--kiosk-type-start-hint);
  letter-spacing: 0.08em;
  color: var(--kiosk-text-primary);
  z-index: 2;
  transition: opacity var(--kiosk-dur-fade) var(--kiosk-ease);
}
.kv-screen--start:not(.is-idle) > .kv-welcome,
.kv-screen--start:not(.is-idle) > .kv-start-hint {
  opacity: 0;
}
.kv-screen--start:not(.is-idle) > .kv-welcome {
  transform: translateY(-12px);
}
/* v4.3.3 ① 打烊 = 待命「睡著」的狀態（設計師 2026-11-03：打烊畫面要跟待命一樣漂亮）：同一張 start 畫面加 .is-closed——輪播照跑、整體壓暗、火星照舊，
   底部提示字換成休息句 + 營業時間小字；不收音、不開 session（點了只有 Kebbi 說一句）。hours.open 拿掉 .is-closed、提示字換回「點擊任一處」就是 P01 */
.kv-screen--start.is-closed > .kv-art {
  filter: brightness(0.62) saturate(0.9);
  transition: filter 1.2s var(--kiosk-ease);
}
.kv-screen--start.is-closed > .kv-start-hint {
  top: 50%;
  bottom: auto;
  transform: translateY(-50%); /* 設計師 2026-11-03：打烊時文字上下置中（待命時在底部） */
}
.kv-start-hint__sub {
  display: block;
  margin-top: 22px;
  font: var(--kiosk-type-hero-sub);
  letter-spacing: 0.04em;
  color: var(--kiosk-text-secondary);
}
/* 待命時頂列不放（設計稿 P01 沒有 logo、沒在收音也不放收音膠囊）；點了才淡入 */
.kv-screen--start > .kv-topbar {
  opacity: 0;
  transition: opacity var(--kiosk-dur-chrome) var(--kiosk-ease);
}
.kv-screen--start:not(.is-idle) > .kv-topbar {
  opacity: 1;
}

/* 對話框：DS 置中位置（left 212、bottom 44）。待命沒有、**喚醒中（is-cast / is-wait）也沒有**（v4.3 設計師 2026-10-30：對話框一出現就會讓人以為可以講了，
   喚醒中只留火光 + 骨架 + 頂列灰色「啟動中」）；ready → is-open 後 450ms 才以 --sent 彩框淡入（火星正要鑽進膠囊）、800ms 落定「直接說，我在聽」。 */
.kv-screen--start > .kv-pill {
  opacity: 0;
  transition: opacity var(--kiosk-dur-rise) var(--kiosk-ease), box-shadow var(--kiosk-dur-rise) var(--kiosk-ease);
}
.kv-screen--start.is-open > .kv-pill {
  opacity: 1;
  transition-delay: 450ms;
}

/* P01b 內容：AI 一句 + 拍照大卡 + 右欄四顆。is-open 時依序升起（dur-rise 300，間隔 100）。 */
.kv-screen--start > .kv-transcript,
.kv-cap-hero,
.kv-caps {
  opacity: 0;
  transform: translateY(28px);
}
.kv-screen--start.is-open > .kv-transcript,
.kv-screen--start.is-open > .kv-cap-hero,
.kv-screen--start.is-open > .kv-caps {
  animation: kv-rise-in var(--kiosk-dur-rise) var(--kiosk-ease) both;
}
.kv-screen--start.is-open > .kv-cap-hero { animation-delay: 100ms; }
.kv-screen--start.is-open > .kv-caps { animation-delay: 200ms; }
/* 有留下的火星時，順序跟著牠的路徑走：大卡（0.24s 經過）→ 右欄（0.4s）→ AI 那句（0.6s）→ 鑽進收音膠囊（0.8s） */
.kv-screen--start.is-open.is-sweep > .kv-cap-hero { animation-delay: 0ms; }
.kv-screen--start.is-open.is-sweep > .kv-caps { animation-delay: 160ms; }
.kv-screen--start.is-open.is-sweep > .kv-transcript { animation-delay: 360ms; }
@keyframes kv-rise-in {
  from { opacity: 0; transform: translateY(28px); }
  to { opacity: 1; transform: none; }
}
/* AI 一句一行：DS .kv-transcript 預設寬 732（兩行用），這裡放寬到 safe-area 寬 1152 */
.kv-screen--start > .kv-transcript {
  width: var(--kiosk-ai-w);
  max-width: none;
  white-space: nowrap;
}

/* 拍照大卡：不透明底的 Grow 外框走 DS 的雙背景做法（--kiosk-grow-border 4px，同 .kv-photo） */
.kv-cap-hero {
  position: absolute;
  left: var(--kiosk-margin);
  top: 232px;
  width: 736px;
  height: 392px;
  box-sizing: border-box;
  padding: var(--kiosk-grow-border);
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-grow);
  box-shadow: var(--kiosk-glow-cta);
  z-index: 2;
}
.kv-cap-hero__inner {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: calc(var(--kiosk-radius-card) - var(--kiosk-grow-border));
  overflow: hidden;
  background: var(--kiosk-surface-base);
}
.kv-cap-hero__inner > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 60% 45%;
}
.kv-cap-hero__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(10, 10, 10, 0.9) 0%, rgba(10, 10, 10, 0.5) 45%, rgba(10, 10, 10, 0) 75%);
}
.kv-cap-hero__body {
  position: absolute;
  left: 40px;
  top: 40px;
  bottom: 36px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.kv-cap-hero__title {
  font: var(--kiosk-type-cap-hero);
  color: var(--kiosk-text-primary);
  margin-bottom: 24px;
}
.kv-cap-hero__go {
  display: flex;
  align-items: center;
  gap: 16px;
  font: 500 22px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
}
/* 大卡用 DS 既有的 .kv-tap-arrow（版型頁的白色實心圓箭頭），只是改成跟在字前面、不絕對定位 */
.kv-cap-hero__go > .kv-tap-arrow {
  position: static;
  width: 72px;
  height: 72px;
  font-size: 34px;
}

/* 右欄四顆：底色與框線同 chips（glass-tap .16 + line-tap 1.5px，設計師 2026-10-23）、DS 動作列字級（700/30）；右邊描邊圓箭頭是新原語 .kv-tap-arrow--outline */
.kv-caps {
  position: absolute;
  left: 832px;
  top: 232px;
  width: 384px;
  height: 392px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  z-index: 2;
}
.kv-cap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 86px;
  padding: 0 12px 0 32px;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-tap);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1.5px var(--kiosk-line-tap);
  font: var(--kiosk-type-action);
  color: var(--kiosk-text-primary);
}
.kv-tap-arrow--outline {
  position: static;
  width: 58px;
  height: 58px;
  background: transparent;
  color: var(--kiosk-text-primary);
  box-shadow: inset 0 0 0 1.5px var(--kiosk-line-tap);
  font-size: 26px;
}

/* 火光（2026-10-23 第二版，設計師：要有大有小、有疏有密、從點擊處原地散出去、自然消失）。
   .kv-fire 一顆火星：核心亮、外圈橙紅、一層光暈；只動 transform / opacity。大小 3–24px 混用，爆發分四波、每波密度不同。
   結束不飛去別處：散開到定點後慢慢往下墜、同時淡掉。 */
.kv-fire-layer {
  position: absolute;
  inset: 0;
  z-index: 8;
  pointer-events: none;
  overflow: hidden;
}
.kv-fire {
  position: absolute;
  left: 0;
  top: 0;
  width: var(--size);
  height: var(--size);
  border-radius: 50%;
  background: radial-gradient(circle, #fff6e0 0%, #ffd9a0 22%, #ff7a2a 48%, rgb(192 52 26 / 0.6) 72%, transparent 100%);
  box-shadow: 0 0 calc(var(--size) * 1.2) rgb(255 150 60 / 0.75), 0 0 calc(var(--size) * 3) rgb(255 106 43 / 0.35);
  mix-blend-mode: screen;
  opacity: 0;
  will-change: transform, opacity;
}
.kv-fire--big {
  background: radial-gradient(circle, #fffaf0 0%, #ffe2b0 18%, #ff8a3a 42%, rgb(192 52 26 / 0.5) 68%, transparent 100%);
  box-shadow: 0 0 calc(var(--size) * 1.5) rgb(255 170 80 / 0.85), 0 0 calc(var(--size) * 4) rgb(255 106 43 / 0.4);
}
/* 點擊處的核心光：一團暖光脹開再散掉 */
.kv-fire-bloom {
  position: absolute;
  left: 0;
  top: 0;
  width: 520px;
  height: 520px;
  margin: -260px 0 0 -260px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 250, 235, 0.85) 0%, rgba(255, 176, 90, 0.35) 28%, rgba(255, 106, 43, 0) 70%);
  mix-blend-mode: screen;
  opacity: 0;
  will-change: transform, opacity;
}
/* 待命時跑來跑去的火星：就是一顆小火光（同 .kv-fire--big 的樣子、10px），沒有十字、沒有圓框（設計師 2026-10-23），後面拖小火星尾巴 */
.kv-idle-spark {
  position: absolute;
  left: 0;
  top: 0;
  width: 10px;
  height: 10px;
  margin: -5px 0 0 -5px;
  z-index: 3;
  pointer-events: none;
  border-radius: 50%;
  background: radial-gradient(circle, #fffaf0 0%, #ffe2b0 18%, #ff8a3a 42%, rgb(192 52 26 / 0.5) 68%, transparent 100%);
  box-shadow: 0 0 15px rgb(255 170 80 / 0.85), 0 0 40px rgb(255 106 43 / 0.4);
  mix-blend-mode: screen;
  will-change: transform;
  transition: opacity var(--kiosk-dur-fade) var(--kiosk-ease);
}
.kv-screen--start:not(.is-idle) > .kv-idle-spark {
  opacity: 0;
}
/* 點了先看到火花才變背景（設計師 2026-10-27）：tap 後 js/start.js 掛 .is-spark-first 約 450ms（火星飛到手指處 250ms + 爆開 200ms），
   這段背景不模糊、不壓暗、頂列不出現、待命火星不淡（對話框 v4.3 起整個喚醒中都不出，見上面）；拿掉後才照原本的 600ms 過渡變暗。歡迎標與底部提示照常馬上退場（點下去要有立即回饋）。 */
.kv-screen--start.is-spark-first > .kv-art {
  filter: none;
  transform: none;
}
.kv-screen--start.is-spark-first::after {
  opacity: 0;
}
.kv-screen--start.is-spark-first > .kv-pill,
.kv-screen--start.is-spark-first > .kv-topbar {
  opacity: 0;
  transition-delay: 0ms;
}
.kv-screen--start.is-spark-first > .kv-idle-spark {
  opacity: 1;
  transition: none;
}

.kv-screen--start > .kv-idle-spark.is-roaming {
  opacity: 1;
}

/* 骨架（等待時）：五個位置只出 1px 細線的空框，沒有字、沒有底色，不會誘人去點。火星飄過時框線亮一下 Grow 再暗回去。 */
.kv-skel {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--kiosk-dur-rise) var(--kiosk-ease);
}
.kv-skel.is-on {
  opacity: 1;
}
.kv-skel.is-off {
  opacity: 0;
}
.kv-skel__box {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  height: var(--h);
  border-radius: var(--r);
  opacity: 0; /* 火星第一次飄過才淡入（.is-seen），之後留著（設計師 2026-10-23：整組一起出現太突兀） */
  transition: opacity 500ms var(--kiosk-ease), box-shadow 500ms var(--kiosk-ease), background-color 500ms var(--kiosk-ease);
}
.kv-skel__box.is-seen {
  opacity: 1;
}
.kv-skel__box.is-lit {
  transition-duration: 500ms, 150ms, 150ms;
}
/* 骨架樣式（設計師 2026-10-23 選定「只留色塊」）：玻璃底白 .06、沒有線；火星飄過底色亮成 .12。大卡與右欄四顆，AI 那句不出骨架。 */
.kv-skel__box {
  background: rgba(255, 255, 255, 0.06);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
}
.kv-skel__box.is-lit {
  background: rgba(255, 255, 255, 0.12);
}
/* 骨架畫完腦還沒好（v4.2，設計師 2026-10-28）：每格掃一道微光，表示還在進行；不做假進度條。只動 transform */
.kv-skel.is-shimmer .kv-skel__box {
  overflow: hidden;
}
.kv-skel.is-shimmer .kv-skel__box::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, 0.1) 50%, transparent 70%);
  transform: translateX(-100%);
  animation: kv-skel-shimmer 1.6s var(--kiosk-ease) infinite;
}
.kv-skel.is-shimmer .kv-skel__box:nth-child(n + 2)::after {
  animation-delay: 0.25s;
}
@keyframes kv-skel-shimmer {
  0% { transform: translateX(-100%); }
  70%, 100% { transform: translateX(100%); }
}
@media (prefers-reduced-motion: reduce) {
  .kv-skel.is-shimmer .kv-skel__box::after { animation: none; opacity: 0; }
}

/* 對話框三態之間不要跳：高度（84 ↔ 96）、光暈、Grow 環、內容都用過渡。
   對話框一出現就是 --sent（彩框 + 正在啟動），不先出灰框（設計師 2026-10-23：三個狀態連續變太多）；v4.3 起只在 ready 後的那 0.35s 看得到彩框，接著 .is-settling「落定」（--sent → 平常態）。 */
.kv-screen--start > .kv-pill {
  transition: opacity var(--kiosk-dur-rise) var(--kiosk-ease), height 300ms var(--kiosk-ease), box-shadow 400ms var(--kiosk-ease);
}
.kv-screen--start > .kv-pill::before {
  transition: opacity 400ms var(--kiosk-ease);
}
/* 兩組 box-shadow 結構一樣（外光暈 + 內環）才能互相過渡；--sent 的內環透明、起點 / 落定態的外光暈透明 */
.kv-screen--start > .kv-pill.kv-pill--sent {
  box-shadow: var(--kiosk-glow-listen), inset 0 0 0 var(--kiosk-grow-ring) transparent;
}
.kv-screen--start > .kv-pill.is-settling {
  height: var(--kiosk-pill-h);
  box-shadow: 0 0 40px rgba(31, 111, 224, 0), inset 0 0 0 var(--kiosk-grow-ring) var(--kiosk-line-pill); /* Grow 環淡掉時，平常的灰環從底下接上來 */
}
.kv-screen--start > .kv-pill.is-nt,
.kv-screen--start > .kv-pill.is-nt::before {
  transition: none !important; /* 落定後換回平常態的那一格不過渡（環已經是同一條灰線） */
}
.kv-screen--start > .kv-pill.is-settling::before {
  opacity: 0;
}
.kv-screen--start > .kv-pill > .kv-pill__live,
.kv-screen--start > .kv-pill > .kv-pill__status,
.kv-screen--start > .kv-pill > .kv-pill__placeholder {
  transition: opacity 200ms var(--kiosk-ease);
}
.kv-screen--start > .kv-pill.is-settling > .kv-pill__live,
.kv-screen--start > .kv-pill.is-settling > .kv-pill__status {
  opacity: 0;
}
.kv-screen--start > .kv-pill.kv-pill--sent.is-settling > .kv-pill__placeholder {
  display: block;
  position: absolute;
  left: var(--kiosk-pill-pad-x);
  animation: kv-fade-in 200ms var(--kiosk-ease) 150ms both;
}

@media (prefers-reduced-motion: reduce) {
  .kv-start-frame { animation: none; }
  .kv-screen--start > *, .kv-screen--start::after { transition: none !important; animation-duration: 1ms !important; }
}

/* @promo-handoff:start —— 這兩行中間是「機器人能幹嘛」段，tools/promo-handoff.mjs 會整段匯出給設計師、改完再整段換回來；不要把別的規則放進來 */
/* ============================================================ v5.1 · Side F 待命「機器人能幹嘛」段（設計師 2026-10-30 晚：三張卡、17/9/9、字放大）（.kv-side-promo）
   v5（Claude Design 2026-10-28，design_handoff_side_f_what_i_can_do_v2，取代 v4.2 的紙本輪播；2026-10-30 白天從 v6 漫畫格退回 v5）：**只改舞台上的卡**，
   頂列、提示、小標、背景、火光、底部曬衣繩索引的結構與動畫沿用 v4.2。
   **v5.1（設計師 2026-10-30 晚）**：離 3–5 公尺看不清、五張 7s 一張看不完 →
   - 五張變三張：01 拍照留念 / 02 活動好康（兩張海報 + 斗篷毯，v4.3.4）/ 03 場次 · 預告 · 新片（票 + 底片 + 日期貼紙，v4.3.4）（原 03 看預告 · 聊新片：底片 + 海報月曆）；索引也三個。
   - 時間 01 17s · 02 9s · 03 9s（一圈仍 35s）：每張卡 / 索引用 --at 帶起始秒數當 animation-delay（原本 --i × 7s），
     紙的進出場與索引點亮的 keyframes 分 9s 版（預設）和 17s 版（.kv-promo-item--long / .kv-promo-hang--long 用 --promo-kf-* 換名字）。
   - 字放大（字級集中在下面 --promo-fs-*）：標題牌 72 → 96、便利貼 44 → 60、卡內副文字 36 → 48、索引 32 → 44、索引小道具 ×1.3；卡框 952×900 → 952×1000。
   - 卡共用骨架：左上紅色號碼牌（.kv-promo-head，編號 + 標題）固定位置；道具在中段固定區；底下一句補充（.kv-promo-sheet__foot）同一條線。
     .kv-promo-sheet 只是透明幾何框（底紙試過、拿掉）。
   - 「我可以幫你做這些事」改便利貼（上緣一條紙膠帶）。拿掉頂列 DISNEY 小字、各卡右上 meta、票上 ADMIT ONE / NO. / TODAY、COMBO 小字。
   - 兩拍進場：卡落下 0.4s 後道具（.kv-promo-prop）再貼上去。各卡小動態：01 兩張限動框 3.5s 換手、02 16:50 紅圈蓋章、03「本檔限定」蓋章 +
     「爆米花 + 飲料」微彈、04 底片三格每 2.33s 輪一張劇照、05 月曆從「週三 11/25 還有一天」翻到「週四 11/26 全台上映」；紙膠帶 5s 微呼吸。
   - 火光 14 顆（原 10 + 卡片左右邊緣 4 顆，實機吃力先砍這 4 顆）。
   一圈 --kiosk-dur-promo（35s），三張卡 01 00–17 · 02 17–26 · 03 26–35。全部 CSS 動畫；實機交付是
   tools/export-side-video.mjs 輸出的 side-f-promo.mp4（side-f.html 用 getAnimations().currentTime 逐格定位）。
   markup 由 js/side-promo.js 產生（DS 頁、side-f.html、promo-review.html 共用）。
   只在待命（沒有 session）播；輪播順序見 README §5.6（Side 播放原則待定）。 */
.kv-side-promo {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--kiosk-surface-base);
  /* v5.1 字級（設計師 2026-10-30 晚：3–5 公尺要看得清） */
  --promo-fs-title: 96px; /* 紅色號碼牌標題 */
  --promo-fs-lead: 60px; /* 便利貼 */
  --promo-fs-foot: 56px; /* 卡底一句補充（設計師 2026-11-03：48 → 56，再大一些） */
  --promo-fs-index: 44px; /* 曬衣繩索引 */
  /* 卡進出場 / 索引點亮的 keyframes，預設 9s 版；17s 那張換長版 */
  --promo-kf-paper: kv-promo-paper;
  --promo-kf-hang: kv-promo-hang;
  --promo-kf-lit: kv-promo-lit;
}
.kv-promo-item--long {
  --promo-kf-paper: kv-promo-paper-long;
}
.kv-promo-hang--long {
  --promo-kf-hang: kv-promo-hang-long;
  --promo-kf-lit: kv-promo-lit-long;
}
.kv-side-promo__bg {
  position: absolute;
  inset: -60px;
  width: calc(100% + 120px);
  height: calc(100% + 120px);
  object-fit: cover;
  filter: blur(40px) brightness(0.3) saturate(130%);
}
.kv-side-promo::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle 600px at 540px 1120px, rgba(255, 176, 90, 0.24), rgba(255, 106, 43, 0) 70%);
}
.kv-side-promo__top {
  position: absolute;
  left: 64px;
  right: 64px;
  top: 80px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
}
.kv-side-promo__eyebrow {
  font: 500 24px/1 var(--kiosk-font-mono);
  letter-spacing: 0.1em;
  color: var(--kiosk-camp);
}
/* 右上角 Vyin AI logo 2026-10-30 晚設計師拿掉（.kv-side-promo__top 不再輸出），提示字往上放、頂部不擠 */
/* 提示字 .kv-marquee 本體在檔案前段（v4.3 起共用給 Side F 使用中態）；這裡只補它在輪播裡的 35s 淡入淡出，位置往上到 96（原 150） */
.kv-side-promo > .kv-marquee {
  top: 96px;
  animation: kv-promo-fade9 var(--kiosk-dur-promo) cubic-bezier(0.2, 0.7, 0.2, 1) infinite both;
}
.kv-side-promo__lead {
  position: absolute;
  left: 0;
  right: 0;
  top: 250px; /* 2026-10-30 晚：三塊拉開——提示 96、便利貼 250、舞台 400、索引 +40 */
  width: max-content;
  margin: 0 auto;
  padding: 28px 52px;
  border-radius: 4px;
  background: var(--kiosk-promo-paper-2);
  box-shadow:
    0 2px 2px rgba(0, 0, 0, 0.3),
    0 20px 40px rgba(0, 0, 0, 0.45);
  rotate: -1.5deg;
  font: 900 var(--promo-fs-lead) / 1 var(--kiosk-font-ui);
  letter-spacing: 0.04em;
  color: var(--kiosk-promo-ink);
  animation: kv-promo-fade9 var(--kiosk-dur-promo) cubic-bezier(0.2, 0.7, 0.2, 1) infinite both;
}
/* 便利貼的紙膠帶：正中上緣一條，跟下面紅色號碼牌區分開 */
.kv-side-promo__lead::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -24px;
  width: 200px;
  height: 52px;
  margin-left: -100px;
  background: var(--kiosk-promo-tape);
  rotate: -3deg;
}
.kv-side-promo__stage {
  position: absolute;
  left: 64px;
  top: var(--card-top, 420px); /* tweak=index 可調 */ /* 卡內容縮 0.84 後整組落在便利貼與索引線中間（2026-10-31 上移 90 給曬衣繩空間） */
  width: 952px;
  height: 1060px; /* 2026-10-30 晚：卡片（含紅牌）落在 508–1540，上離便利貼 375 約 130、下離索引線 1600 有 60 */
}
.kv-promo-item {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  animation: var(--promo-kf-paper) var(--kiosk-dur-promo) var(--at, 0s) cubic-bezier(0.2, 0.7, 0.2, 1) infinite;
}
.kv-promo-item:first-child {
  opacity: 1;
}
.kv-promo-tape {
  position: absolute;
  width: 150px;
  height: 46px;
  background: var(--kiosk-promo-tape);
}
.kv-promo-num {
  font: 500 36px/1 var(--kiosk-font-mono);
  letter-spacing: 0.1em;
  color: var(--kiosk-promo-red);
}
.kv-promo-meta {
  font: 500 24px/1 var(--kiosk-font-mono);
  letter-spacing: 0.1em;
  color: var(--kiosk-promo-ink-2);
}

/* ===== 三件事都印在同一款傳單上（.kv-promo-sheet） =====
   骨架一致：左上角一張紅色標題牌（編號 + 標題，固定位置、固定字級 --promo-fs-title）、
   下面 952×1000 的幾何框放這件事的道具；紙面上的主要字 ≥ 56。三張只差內容，不差構圖。 */
/* 底紙拿掉（設計師 2026-10-28）：只留它的幾何當共同骨架，道具直接貼在背景上 */
.kv-promo-sheet {
  position: relative;
  width: 952px;
  height: 960px; /* v5.1：900 → 1000 合併卡放兩組道具；2026-10-30 晚收到 960、餐券上移，底部索引才有呼吸 */
  margin-top: 60px;
  rotate: var(--tilt, -1.2deg);
}
.kv-promo-sheet::before,
.kv-promo-sheet::after,
.kv-promo-sheet > .kv-promo-tape {
  display: none;
}
/* 道具共用：紙落下 0.4 秒後再「貼」上去 */
.kv-promo-prop {
  animation: kv-promo-stick var(--kiosk-dur-promo) var(--at, 0s) cubic-bezier(0.2, 0.7, 0.2, 1) infinite;
}
@keyframes kv-promo-stick {
  0%,
  1.6% {
    opacity: 0;
    transform: translateY(-36px) scale(1.05);
  }
  3% {
    opacity: 1;
    transform: none;
  }
  100% {
    opacity: 1;
    transform: none;
  }
}
/* 蓋章：從大落下、微回彈 */
@keyframes kv-promo-chop {
  0%,
  4% {
    opacity: 0;
    transform: scale(1.9);
  }
  4.5% {
    opacity: 1;
    transform: scale(0.94);
  }
  4.9% {
    transform: scale(1);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}
.kv-promo-sheet > .kv-promo-tape {
  top: -20px;
  z-index: 2;
}
.kv-promo-tape {
  animation: kv-promo-tape-breathe 5s ease-in-out infinite;
}
@keyframes kv-promo-tape-breathe {
  0%,
  100% {
    translate: 0 0;
    opacity: 1;
  }
  50% {
    translate: 0 1.5px;
    opacity: 0.92;
  }
}
.kv-promo-sheet > .kv-promo-tape:nth-of-type(1) {
  left: 40px;
  rotate: -6deg;
}
.kv-promo-sheet > .kv-promo-tape:nth-of-type(2) {
  right: 40px;
  rotate: 5deg;
}
/* 標題牌：壓在紙的上緣，像釘在上面的紅色號碼牌。這是每張卡視線先找到的東西，所以永遠同一個位置 */
.kv-promo-head {
  position: absolute;
  left: 40px;
  top: -52px;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 30px;
  padding: 24px 48px 24px 36px;
  border-radius: 8px;
  background: var(--kiosk-promo-red);
  box-shadow:
    0 2px 2px rgba(0, 0, 0, 0.3),
    0 18px 36px rgba(0, 0, 0, 0.4);
  rotate: -1.5deg;
  white-space: nowrap;
}
.kv-promo-head .kv-promo-num {
  font-size: 44px;
  color: var(--kiosk-promo-paper);
  opacity: 0.85;
}
.kv-promo-head__title {
  font: 900 var(--promo-fs-title) / 1 var(--kiosk-font-ui);
  letter-spacing: 0.02em;
  color: var(--kiosk-promo-paper);
}
/* 紙面內容區：標題牌下方到紙底 */
.kv-promo-sheet__body {
  position: absolute;
  left: 56px;
  right: 56px;
  top: 190px; /* 紅牌底下留 60 再開始放道具 */
  bottom: 56px;
  transform: scale(0.84); /* 2026-10-30 晚設計師：卡內道具整體縮小，不壓到紅牌、不壓到底下那句；字級用大的留給紅牌 / 便利貼 / 索引 */
  transform-origin: 50% 0;
}
/* 紙面最底一句補充：三張都在同一條線上 */
.kv-promo-sheet__foot {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -96px; /* 2026-10-30 晚：道具往下挪 70 後，補充句跟著掉到紙面下方，離道具 ≥ 40 */
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 24px;
  font: 500 var(--promo-fs-foot) / 1 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
  white-space: nowrap;
}
.kv-promo-sheet__foot b {
  font-weight: 700;
  color: var(--kiosk-promo-paper);
}
.kv-promo-sheet__foot i {
  width: 3px;
  height: 42px;
  background: rgba(243, 234, 216, 0.3);
}

/* 01 拍照：兩張限動框疊在紙上，中間換手（前面那張退到後面），像翻看照片 */
.kv-promo-photos {
  position: absolute;
  left: 0;
  right: 0;
  top: 10px;
  height: 600px; /* 2026-10-30 晚：限動框再縮，離底下補充句遠一點 */
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: -40px;
}
.kv-promo-photos > div {
  position: relative;
}
.kv-promo-photos > div:nth-child(1) { /* --ph1-* / --ph2-*：side-f.html?tweak=photos 小工具調（預設 = 定案） */
  rotate: var(--ph1-rot, -4deg); /* 設計師 2026-10-30 晚用 tweak=photos 調的定案 */
  translate: var(--ph1-x, -90px) var(--ph1-y, -23px);
  scale: var(--ph1-s, 0.97);
  z-index: 1; /* 設計師 2026-10-30 晚：右邊那張固定在上面，不再 4.25s 換手（兩張框裡的影片本身在動） */
}
.kv-promo-photos > div:nth-child(2) {
  rotate: var(--ph2-rot, 9deg);
  translate: var(--ph2-x, -11px) var(--ph2-y, 0px);
  scale: var(--ph2-s, 1.23);
  z-index: 2;
}
.kv-promo-photos .kv-story {
  --story-w: 380px;
  border-radius: 14px;
  box-shadow:
    0 2px 3px rgba(0, 0, 0, 0.35),
    0 24px 48px rgba(0, 0, 0, 0.4);
}
/* v5.1：01 停 17s；原本兩張每 4.25s 換一次手，2026-10-30 晚設計師改成右邊固定在上（keyframes 留著備用） */
@keyframes kv-promo-swap-a {
  0%,
  12.13%,
  24.29%,
  36.42% {
    z-index: 2;
  }
  12.14%,
  24.28%,
  36.43%,
  100% {
    z-index: 1;
  }
}
@keyframes kv-promo-swap-b {
  0%,
  12.13%,
  24.29%,
  36.42% {
    z-index: 1;
  }
  12.14%,
  24.28%,
  36.43%,
  100% {
    z-index: 2;
  }
}
@keyframes kv-promo-fwd {
  0%,
  11.2%,
  25.2%,
  35.5% {
    transform: none;
  }
  13.1%,
  23.3%,
  37.4%,
  100% {
    transform: scale(0.92) translateY(14px);
  }
}
@keyframes kv-promo-back {
  0%,
  11.2%,
  25.2%,
  35.5% {
    transform: scale(0.92) translateY(14px);
  }
  13.1%,
  23.3%,
  37.4%,
  100% {
    transform: none;
  }
}

/* 01 的真實錄影成品（.kv-promo-real）：整張就是合成好的影片，蓋滿限動框 */
.kv-promo-real > .kv-promo-clip {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* 02 場次（v5.1 原本跟活動好康同一張卡：票在上、活動券在下（v4.3.4））：原本的電影票（道具感，看得出是示意、不是真場次），貼在傳單上；標題在上面的紅牌，票上不重複 */
.kv-promo-ticket {
  position: absolute;
  left: -16px;
  top: 0;
  display: flex;
  width: 872px;
  height: 300px;
  border-radius: 24px;
  background: var(--kiosk-promo-paper-2);
  box-shadow:
    0 2px 3px rgba(0, 0, 0, 0.25),
    0 24px 48px rgba(0, 0, 0, 0.3),
    0 0 0 2px rgba(29, 23, 18, 0.08);
  rotate: 1.5deg;
  -webkit-mask:
    radial-gradient(circle 26px at 70% 0, #0000 97%, #000) top / 100% 51% no-repeat,
    radial-gradient(circle 26px at 70% 100%, #0000 97%, #000) bottom / 100% 51% no-repeat;
  mask:
    radial-gradient(circle 26px at 70% 0, #0000 97%, #000) top / 100% 51% no-repeat,
    radial-gradient(circle 26px at 70% 100%, #0000 97%, #000) bottom / 100% 51% no-repeat;
}
.kv-promo-ticket__main {
  width: 70%;
  padding: 32px 40px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 28px;
  white-space: nowrap;
}
.kv-promo-ticket__film {
  font: 900 60px/1 var(--kiosk-font-ui);
  color: var(--kiosk-promo-ink);
}
.kv-promo-ticket__times {
  display: flex;
  gap: 24px;
  align-items: center;
  font: 600 44px/1 var(--kiosk-font-mono);
  color: var(--kiosk-promo-ink);
}
.kv-promo-ticket__times b {
  position: relative;
  font-weight: 600;
  padding: 8px 16px;
  color: var(--kiosk-promo-red);
}
/* 16:50 的紅圈是蓋上去的章 */
.kv-promo-ticket__times b::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 4px solid var(--kiosk-promo-red);
  border-radius: 999px;
  opacity: 0.9;
  animation: kv-promo-chop var(--kiosk-dur-promo) var(--at, 0s) cubic-bezier(0.2, 0.9, 0.3, 1.3) infinite;
}
.kv-promo-ticket__stub {
  flex: 1;
  border-left: 3px dashed rgba(29, 23, 18, 0.28);
  display: flex;
  align-items: center;
  justify-content: center;
}
.kv-promo-ticket__no {
  font: 600 120px/1 var(--kiosk-font-mono);
  color: var(--kiosk-promo-red);
}
/* 03 場次 · 預告（v4.3.4 第三輪，設計師：場次卡小一點、字精簡）：票縮成 760×200 一列，底片在下面 */
.kv-promo-ticket--sm {
  left: 40px;
  width: 760px;
  height: 200px;
  rotate: 1deg;
}
.kv-promo-ticket--sm .kv-promo-ticket__main {
  flex-direction: row;
  align-items: center;
  gap: 24px;
  padding: 24px 32px;
}
.kv-promo-ticket--sm .kv-promo-ticket__film {
  font-size: 48px;
}
.kv-promo-ticket--sm .kv-promo-ticket__times {
  font-size: 32px;
}
.kv-promo-ticket--sm .kv-promo-ticket__times b {
  padding: 6px 14px;
}
.kv-promo-ticket--sm .kv-promo-ticket__no {
  font-size: 84px;
}

/* 02 活動好康（v4.3.4，設計師 2026-11-03 第三輪：「做成兩張卡片」）：上下兩張紙卡（同票的紙 + 陰影），各自一個紅圈標籤 + 大標 + 一行說明，右邊放照片——
   A 預購送海報（兩張海報疊貼）、B 合照換斗篷毯（斗篷毯去背圖 + 「同框禮」圓章）；不分上映前後 */
.kv-promo-gift {
  position: absolute;
  left: 0;
  right: 0;
  height: 290px;
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 0 24px 0 56px;
  box-sizing: border-box;
  background: var(--kiosk-promo-paper-2);
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.25)) drop-shadow(0 24px 30px rgba(0, 0, 0, 0.4));
}
/* 兌換券的上下鋸齒邊（設計師 2026-11-03 第四輪：卡片要可愛有趣一點）——沿用原本餐券的做法 */
.kv-promo-gift::before {
  content: "";
  position: absolute;
  inset: -18px 0;
  background: var(--kiosk-promo-paper-2);
  -webkit-mask:
    conic-gradient(from -45deg at bottom, #0000, #000 1deg 89deg, #0000 90deg) bottom / 36px 51% repeat-x,
    conic-gradient(from 135deg at top, #0000, #000 1deg 89deg, #0000 90deg) top / 36px 51% repeat-x;
  mask:
    conic-gradient(from -45deg at bottom, #0000, #000 1deg 89deg, #0000 90deg) bottom / 36px 51% repeat-x,
    conic-gradient(from 135deg at top, #0000, #000 1deg 89deg, #0000 90deg) top / 36px 51% repeat-x;
  z-index: -1;
}
.kv-promo-gift--a {
  top: 0;
  rotate: -1deg;
}
/* v4.3.7 上映前沒開斗篷預告：只剩預購禮那張券，放在兩張券原本的中間 */
.kv-promo-gift--solo {
  top: 180px;
  rotate: -1.5deg;
}
.kv-promo-gift--b {
  top: 364px; /* 兩張券的鋸齒邊各往外長 18，中間留 56 才不會黏在一起 */
  rotate: 1deg;
}
.kv-promo-gift__text {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 18px;
  padding-top: 16px; /* 圓貼紙在左上角，標題往下讓一點 */
  white-space: nowrap;
}
.kv-promo-gift__tag {
  position: absolute;
  left: -26px;
  top: -30px;
  width: 112px;
  height: 112px;
  border-radius: 50%;
  background: var(--kiosk-promo-red);
  box-shadow:
    inset 0 0 0 5px var(--kiosk-promo-paper-2),
    inset 0 0 0 8px var(--kiosk-promo-red),
    0 6px 12px rgba(0, 0, 0, 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  rotate: -12deg;
  font: 900 30px/1.1 var(--kiosk-font-ui);
  text-align: center;
  color: var(--kiosk-promo-paper-2);
}
.kv-promo-gift__title {
  font: 900 56px/1 var(--kiosk-font-ui);
  color: var(--kiosk-promo-ink);
}
.kv-promo-gift__sub {
  font: 500 32px/1 var(--kiosk-font-ui);
  color: var(--kiosk-promo-ink-2);
}
.kv-promo-gift__visual {
  position: relative;
  flex: none;
  width: 340px;
  height: 280px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.kv-promo-gift__visual .kv-promo-poster {
  display: block;
  position: absolute;
  top: 28px;
  width: 150px;
  height: 216px;
}
.kv-promo-gift__visual .kv-promo-poster:first-child {
  left: 24px;
  rotate: -6deg;
}
.kv-promo-gift__visual .kv-promo-poster:last-child {
  left: 164px;
  top: 44px;
  rotate: 5deg;
}
/* v4.3.7：兌換券右下圓章「11/26 開始」/「已送完」；送完整張壓暗 */
.kv-promo-gift .kv-promo-stamp {
  right: 22px;
  bottom: 18px;
  width: 128px;
  height: 128px;
  font-size: 30px;
  rotate: -10deg;
}
/* 斗篷那張券的圓章放右上角翹出券外，不壓到斗篷圖（v4.3.7） */
.kv-promo-gift--b .kv-promo-stamp {
  top: -34px;
  right: 28px;
  bottom: auto;
  font-size: 24px;
}
.kv-promo-gift__visual .kv-promo-tape {
  scale: 0.62; /* 設計師 2026-11-03：海報上的膠帶小一點 */
}
/* 斗篷毯正反面（設計師 2026-11-03 給背面圖）：背面斜放在後、正面在前 */
.kv-promo-gift__visual--cloak > img {
  position: absolute;
  height: 262px;
  filter: drop-shadow(0 14px 20px rgba(0, 0, 0, 0.35));
}
.kv-promo-gift__visual--cloak > img:first-child {
  left: 130px;
  top: 24px;
  rotate: 10deg;
  filter: drop-shadow(0 14px 20px rgba(0, 0, 0, 0.35)) brightness(0.92);
}
.kv-promo-gift__visual--cloak > img:last-child {
  left: 10px;
  top: 12px;
  rotate: -6deg;
}
.kv-promo-gift__visual > img {
  height: 270px;
  filter: drop-shadow(0 18px 24px rgba(0, 0, 0, 0.35));
}
.kv-promo-gift .kv-promo-stamp {
  width: 120px;
  height: 120px;
  right: 16px;
  bottom: 14px;
  font-size: 34px;
}
.kv-promo-stamp {
  position: absolute;
  right: 36px;
  bottom: 28px;
  width: 160px;
  height: 160px;
  border: 6px solid var(--kiosk-promo-red);
  border-radius: 50%;
  box-shadow:
    inset 0 0 0 6px var(--kiosk-promo-paper-2),
    inset 0 0 0 9px var(--kiosk-promo-red);
  display: flex;
  align-items: center;
  justify-content: center;
  font: 900 44px/1.15 var(--kiosk-font-ui);
  text-align: center;
  color: var(--kiosk-promo-red);
  rotate: 12deg;
  opacity: 0.9;
  animation: kv-promo-chop var(--kiosk-dur-promo) var(--at, 0s) cubic-bezier(0.2, 0.9, 0.3, 1.3) infinite;
}

/* 03 預告（v5.1 跟新片資訊同一張卡：底片在上、海報 + 月曆在下）：原本的底片（三格劇照 + 底片上印字），貼在傳單上；底片上印「▶ 正式預告」，標題在紅牌不重複 */
.kv-promo-film {
  position: absolute;
  left: 0;
  right: 0;
  top: var(--film-top, 90px); /* 2026-10-31 設計師：03 的膠片 + 日曆整組往下，離紅牌遠一點 */
  padding: 48px 32px 92px; /* 2026-10-30 晚：底下黑邊加寬，「正式預告」那排不擠 */
  box-sizing: border-box;
  border-radius: 10px;
  background: var(--kiosk-promo-film);
  box-shadow:
    0 2px 3px rgba(0, 0, 0, 0.4),
    0 24px 48px rgba(0, 0, 0, 0.35);
  rotate: -1.5deg;
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.kv-promo-film::before,
.kv-promo-film::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 22px;
  background: repeating-linear-gradient(90deg, transparent 0 18px, var(--kiosk-promo-paper) 18px 44px, transparent 44px 62px);
}
.kv-promo-film::before {
  top: 16px;
}
.kv-promo-film::after {
  bottom: 16px;
}
.kv-promo-film__frames {
  display: flex;
  gap: 16px;
  height: 210px;
}
/* 每格疊三張劇照，每 3 秒輪一張（三格錯開；v5.1 這張卡 9s 剛好一輪），像底片在走 */
.kv-promo-film__frame {
  position: relative;
  flex: 1;
  min-width: 0;
  height: 100%;
  border-radius: 6px;
  overflow: hidden;
  background: #000;
}
.kv-promo-film__frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: sepia(0.35) brightness(0.85);
  opacity: 0;
  animation: var(--reel) var(--kiosk-dur-promo) var(--at, 0s) steps(1, end) infinite;
}
@keyframes kv-promo-reel0 {
  0%,
  8.56% {
    opacity: 1;
  }
  8.57%,
  25.7% {
    opacity: 0;
  }
  25.71%,
  100% {
    opacity: 1;
  }
}
@keyframes kv-promo-reel1 {
  0%,
  8.56% {
    opacity: 0;
  }
  8.57%,
  17.13% {
    opacity: 1;
  }
  17.14%,
  100% {
    opacity: 0;
  }
}
@keyframes kv-promo-reel2 {
  0%,
  17.13% {
    opacity: 0;
  }
  17.14%,
  25.7% {
    opacity: 1;
  }
  25.71%,
  100% {
    opacity: 0;
  }
}
.kv-promo-film__foot {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.kv-promo-film__title {
  font: 900 64px/1 var(--kiosk-font-ui);
  color: var(--kiosk-promo-paper);
}
.kv-promo-film__meta {
  font: 600 44px/1 var(--kiosk-font-mono);
  color: var(--kiosk-camp);
}

/* 上映前 / 上映後兩版（設計師 2026-10-28）：票上不寫示意時間（路人會當真）、改「今天的場次」蓋紅圈章；曬衣繩小票同步寫「場次」 */
.kv-promo-ticket__times .kv-promo-ticket__today {
  padding: 10px 26px;
  font: 900 52px/1 var(--kiosk-font-ui);
  letter-spacing: 0.04em;
}
.kv-promo-mini--word {
  font: 900 42px/1 var(--kiosk-font-ui);
}
/* 上映後月曆：大字「熱映中」 */
.kv-promo-cal__day--word {
  margin: 38px 0 26px;
  font: 900 48px/1 var(--kiosk-font-ui); /* 2026-10-31 設計師：68 → 48 */ /* 設計師 2026-10-28：100 太大；v5.1 月曆縮到 340 寬再降一級 */
  letter-spacing: 0.02em;
}

/* 新片資訊（v5.1 併進 03，疊在底片下面）：左海報（有字的黃色門版）、右月曆 */
.kv-promo-info {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--cal-top, 251px) + var(--film-top, 90px)); /* 設計師 2026-10-30 晚用 tweak=cal 調的定案：251 / -2deg / -91 / 370；跟著膠片一起下移 */ /* 2026-10-30 晚設計師：海報拿掉，只留膠片 + 日期貼紙疊在膠片右下。四個 --cal-* 變數給 side-f.html?tweak=cal 的小工具現場調（預設值 = 定案） */
  height: auto;
  justify-content: flex-end;
  padding-right: 0;
  display: flex;
  gap: 40px;
  align-items: center;
}
.kv-promo-poster {
  display: none; /* 2026-10-30 晚：03 不放海報 */
  position: relative;
  flex: none;
  width: 210px;
  height: 300px;
  rotate: -3deg;
}
.kv-promo-poster__sheet {
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 8px;
  box-shadow:
    0 2px 3px rgba(0, 0, 0, 0.3),
    0 24px 48px rgba(0, 0, 0, 0.35);
}
.kv-promo-poster__sheet > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.kv-promo-poster .kv-promo-tape {
  left: 30px;
  top: -20px;
  rotate: 3deg;
}
.kv-promo-info__col {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 36px;
}
.kv-promo-cal {
  width: var(--cal-w, 370px);
  rotate: var(--cal-rot, -2deg);
  margin-left: auto; /* 貼在膠片右下 */
  margin-right: var(--cal-right, -91px); /* 可以是負的（超出膠片右邊） */
  border-radius: 10px;
  overflow: hidden;
  background: var(--kiosk-promo-paper-2);
  box-shadow:
    0 2px 3px rgba(0, 0, 0, 0.25),
    0 24px 48px rgba(0, 0, 0, 0.3);
  display: flex;
  flex-direction: column;
  align-items: center;
  rotate: 3deg;
  perspective: 900px;
}
/* 月曆翻頁：11/25 那頁從上緣翻起、落到 11/26 */
.kv-promo-cal__page {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background: var(--kiosk-promo-paper-2);
  display: flex;
  flex-direction: column;
  align-items: center;
  transform-origin: 50% 0;
  backface-visibility: hidden;
  box-shadow: 0 -6px 14px rgba(0, 0, 0, 0.12);
  animation: kv-promo-flip var(--kiosk-dur-promo) var(--at, 0s) cubic-bezier(0.5, 0, 0.8, 0.4) infinite;
}
.kv-promo-cal__page .kv-promo-cal__day {
  color: var(--kiosk-promo-ink-2);
}
.kv-promo-cal__page .kv-promo-cal__note {
  color: var(--kiosk-promo-ink-2);
}
@keyframes kv-promo-flip {
  0%,
  4.6% {
    transform: rotateX(0);
    opacity: 1;
  }
  5.8% {
    transform: rotateX(-110deg);
    opacity: 1;
  }
  5.81%,
  100% {
    transform: rotateX(-110deg);
    opacity: 0;
  }
}
.kv-promo-cal__month {
  align-self: stretch;
  height: 70px;
  background: var(--kiosk-promo-red);
  display: flex;
  align-items: center;
  justify-content: center;
  font: 700 34px/1 var(--kiosk-font-ui);
  letter-spacing: 0.2em;
  color: var(--kiosk-promo-paper);
}
.kv-promo-cal__day {
  margin: 22px 0 8px;
  font: 600 104px/1 var(--kiosk-font-mono);
  letter-spacing: -0.04em;
  color: var(--kiosk-promo-ink);
}
.kv-promo-cal__note {
  margin-bottom: 26px;
  font: 900 42px/1 var(--kiosk-font-ui);
  color: var(--kiosk-promo-red);
}

/* ===== 曬衣繩索引（v5.1：三個、字 44、小道具 ×1.3，繩子上移 30 騰出高度） ===== */
.kv-promo-line {
  z-index: 1; /* 線在小道具底下 */
  position: absolute;
  left: 52px;
  right: 52px;
  top: var(--idx-line, 1500px); /* 2026-10-31：曬衣線位置，tweak=index 可調 */ /* 2026-10-30 晚：卡底現在在 1480 左右，索引整組上移，底下留空不貼邊 */
  height: 42px;
  border-bottom: 3px solid rgba(243, 234, 216, 0.55);
  border-radius: 0 0 50% 50% / 0 0 100% 100%;
  animation: kv-promo-fade15 var(--kiosk-dur-promo) cubic-bezier(0.2, 0.7, 0.2, 1) infinite both;
}
.kv-promo-hang {
  position: absolute;
  left: var(--x);
  top: calc(var(--idx-line, 1500px) + 10px); /* 跟著曬衣線；三個各自的距線在下面 --1/2/3 */
  width: 340px;
  display: flex;
  flex-direction: column;
  align-items: center;
  z-index: 2; /* 2026-10-31 設計師：三個小道具永遠在曬衣線上面（含沒 active 的） */
  scale: var(--idx-s, 0.98);
  transform-origin: 50% 0;
  animation: kv-promo-fade15 var(--kiosk-dur-promo) cubic-bezier(0.2, 0.7, 0.2, 1) infinite both;
}
/* 三個小道具高度不同，距線 / 左右可以各自調（tweak=index）；2026-10-31 早上這段曾被我插壞（width 等掉進 --3），已修 */
.kv-promo-hang--1 {
  top: calc(var(--idx-line, 1500px) + var(--idx-gap1, 25px));
  translate: var(--idx-x1, 4px) 0;
}
.kv-promo-hang--2 {
  top: calc(var(--idx-line, 1500px) + var(--idx-gap2, 34px));
  translate: var(--idx-x2, -12px) 0;
}
.kv-promo-hang--3 {
  top: calc(var(--idx-line, 1500px) + var(--idx-gap3, 23px));
  translate: var(--idx-x3, -12px) 0;
}
.kv-promo-hang__sway {
  transform-origin: 50% 0;
  animation: kv-promo-sway var(--sway, 3.6s) ease-in-out infinite;
}
.kv-promo-hang__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  transform-origin: 50% 0;
  opacity: 0.45;
  animation: var(--promo-kf-hang) var(--kiosk-dur-promo) var(--at, 0s) cubic-bezier(0.2, 0.7, 0.2, 1) infinite;
}
.kv-promo-hang__pin {
  position: relative;
  z-index: 2;
  width: 16px;
  height: 40px;
  margin-bottom: -22px;
  border-radius: 3px;
  background: var(--kiosk-promo-pin);
  box-shadow: 0 2px 0 #8a6a3d;
}
.kv-promo-hang__label {
  margin-top: var(--idx-label, 48px); /* 字跟小道具的距離，tweak=index 可調 */
  display: flex;
  align-items: baseline;
  gap: 12px;
  opacity: 0.4;
  white-space: nowrap;
  animation: var(--promo-kf-lit) var(--kiosk-dur-promo) var(--at, 0s) linear infinite;
}
.kv-promo-hang__label .kv-promo-num {
  font-size: 32px;
  color: var(--kiosk-camp);
}
.kv-promo-hang__label b {
  font: 900 var(--promo-fs-index) / 1 var(--kiosk-font-ui);
  color: var(--kiosk-promo-paper);
}
.kv-promo-mini {
  box-shadow:
    0 2px 2px rgba(0, 0, 0, 0.35),
    0 14px 28px rgba(0, 0, 0, 0.45);
}
.kv-promo-mini--photo {
  width: 146px;
  padding: 12px 12px 34px;
  box-sizing: border-box;
  border-radius: 4px;
  background: var(--kiosk-promo-paper-2);
}
.kv-promo-mini--photo img {
  display: block;
  width: 122px;
  height: 125px;
  object-fit: cover;
}
.kv-promo-mini--ticket {
  width: 196px;
  height: 120px;
  border-radius: 14px;
  background: var(--kiosk-promo-paper);
  display: flex;
  align-items: center;
  justify-content: center;
  font: 600 42px/1 var(--kiosk-font-mono);
  color: var(--kiosk-promo-red);
  -webkit-mask:
    radial-gradient(circle 14px at 0 50%, #0000 97%, #000) left / 51% 100% no-repeat,
    radial-gradient(circle 14px at 100% 50%, #0000 97%, #000) right / 51% 100% no-repeat;
  mask:
    radial-gradient(circle 14px at 0 50%, #0000 97%, #000) left / 51% 100% no-repeat,
    radial-gradient(circle 14px at 100% 50%, #0000 97%, #000) right / 51% 100% no-repeat;
}
.kv-promo-mini--coupon {
  width: 196px;
  height: 120px;
  background: var(--kiosk-promo-paper-2);
  display: flex;
  align-items: center;
  justify-content: center;
  font: 900 44px/1 var(--kiosk-font-ui);
  color: var(--kiosk-promo-red);
  -webkit-mask:
    conic-gradient(from -45deg at bottom, #0000, #000 1deg 89deg, #0000 90deg) bottom / 16px 51% repeat-x,
    conic-gradient(from 135deg at top, #0000, #000 1deg 89deg, #0000 90deg) top / 16px 51% repeat-x;
  mask:
    conic-gradient(from -45deg at bottom, #0000, #000 1deg 89deg, #0000 90deg) bottom / 16px 51% repeat-x,
    conic-gradient(from 135deg at top, #0000, #000 1deg 89deg, #0000 90deg) top / 16px 51% repeat-x;
}
.kv-promo-mini--film {
  position: relative;
  width: 196px;
  height: 130px;
  padding: 30px 13px;
  box-sizing: border-box;
  border-radius: 6px;
  background: var(--kiosk-promo-film);
}
.kv-promo-mini--film::before,
.kv-promo-mini--film::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 12px;
  background: repeating-linear-gradient(90deg, transparent 0 10px, var(--kiosk-promo-paper) 10px 22px, transparent 22px 30px);
}
.kv-promo-mini--film::before {
  top: 8px;
}
.kv-promo-mini--film::after {
  bottom: 8px;
}
.kv-promo-mini--film img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 3px;
  filter: sepia(0.35) brightness(0.85);
}
.kv-promo-mini--poster {
  position: relative;
  width: 124px;
  height: 172px;
  overflow: hidden;
  border-radius: 4px;
  background: var(--kiosk-promo-red);
}
.kv-promo-mini--poster img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 40%;
}
.kv-side-promo > .kv-embers {
  z-index: 0;
  animation: none;
}

@keyframes kv-promo-fade9 {
  0%,
  3.2% {
    opacity: 0;
    transform: translateY(30px);
  }
  4.6%,
  97.9% {
    opacity: 1;
    transform: none;
  }
  100% {
    opacity: 0;
    transform: none;
  }
}
@keyframes kv-promo-fade15 {
  0%,
  5.4% {
    opacity: 0;
    transform: translateY(30px);
  }
  6.8%,
  97.9% {
    opacity: 1;
    transform: none;
  }
  100% {
    opacity: 0;
    transform: none;
  }
}
/* 卡進出場：9s 版（02 / 03）。百分比是 35s 的比例：卡停到 8.755s（25.01%）、9.245s（26.41%）落下消失 */
@keyframes kv-promo-paper {
  0% {
    opacity: 0;
    transform: translateY(-160px) rotate(-6deg) scale(1.04);
  }
  1.43% {
    opacity: 1;
    transform: translateY(12px) rotate(1deg);
  }
  2.14%,
  25.01% {
    opacity: 1;
    transform: none;
  }
  26.41% {
    opacity: 0;
    transform: translateY(90px) rotate(2deg);
  }
  100% {
    opacity: 0;
    transform: translateY(90px);
  }
}
/* 17s 版（01 拍照）：停到 16.755s（47.87%）、17.245s（49.27%）落下 */
@keyframes kv-promo-paper-long {
  0% {
    opacity: 0;
    transform: translateY(-160px) rotate(-6deg) scale(1.04);
  }
  1.43% {
    opacity: 1;
    transform: translateY(12px) rotate(1deg);
  }
  2.14%,
  47.87% {
    opacity: 1;
    transform: none;
  }
  49.27% {
    opacity: 0;
    transform: translateY(90px) rotate(2deg);
  }
  100% {
    opacity: 0;
    transform: translateY(90px);
  }
}
/* 索引點亮：9s 版亮到 25.71%（9s）；17s 版亮到 48.57%（17s） */
@keyframes kv-promo-hang {
  0% {
    opacity: 0.45;
    transform: none;
  }
  1.07%,
  25.01% {
    opacity: 1;
    transform: translateY(-6px) scale(1.14);
  }
  25.71%,
  100% {
    opacity: 0.45;
    transform: none;
  }
}
@keyframes kv-promo-hang-long {
  0% {
    opacity: 0.45;
    transform: none;
  }
  1.07%,
  47.87% {
    opacity: 1;
    transform: translateY(-6px) scale(1.14);
  }
  48.57%,
  100% {
    opacity: 0.45;
    transform: none;
  }
}
@keyframes kv-promo-lit {
  0% {
    opacity: 0.4;
  }
  1.07%,
  25.01% {
    opacity: 1;
  }
  25.71%,
  100% {
    opacity: 0.4;
  }
}
@keyframes kv-promo-lit-long {
  0% {
    opacity: 0.4;
  }
  1.07%,
  47.87% {
    opacity: 1;
  }
  48.57%,
  100% {
    opacity: 0.4;
  }
}
@keyframes kv-promo-sway {
  0%,
  100% {
    transform: rotate(-2.5deg);
  }
  50% {
    transform: rotate(2.5deg);
  }
}
@keyframes kv-promo-nudge {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-14px);
  }
}
@media (prefers-reduced-motion: reduce) {
  .kv-side-promo *,
  .kv-side-promo *::before,
  .kv-side-promo *::after {
    animation: none !important;
  }
  .kv-promo-item:first-child,
  .kv-promo-hang__item,
  .kv-promo-hang__label {
    opacity: 1;
  }
}
/* @promo-handoff:end */

/* ============================================================ v4.2 · 場次表（A05t，設計師 2026-10-27 選 B「時刻表」）
   沒指定片名問「今天有什麼場次」（或點 P01b 右欄「查場次」）時出：今天、跨電影、照開演時間排，一頁 5 場，「下一頁」翻頁。
   每一場只放：開演時間、片名（本片用活動色）、版本標籤（IMAX、中文版、英文版…）。**不放剩位、不放廳別**（不用另外撈這兩個資料）。
   每一列可點 = （v4.3.4 退場：場次是最後一頁、不放 QR；原 A05p 活動好康卡 + QR；設計師 2026-10-27 試玩後定：選了場次接著就是買票加套餐）。表格頁不放 QR。
   想看單一部片的場次用說的（對話框提示「想看某一部片的場次，直接說片名」）→ A05 單片場次卡。
   放在 AI 一行（.kv-screen--one-line）的 safe area，往下拉高到 1152×420（底離對話框 28px；設計師 2026-10-27 嫌 388 擠）；一頁 5 場、每列 66（設計師定）。 */
.kv-schedule {
  flex: 1;
  min-width: 0;
  height: 420px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.kv-schedule__panel {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding: 12px; /* 四邊一樣 12：列的圓角 20 = 外框 32 − 12，按下的框跟外框同心（設計師 2026-10-27） */
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-glass-info);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
}
.kv-schedule__row {
  position: relative;
  display: grid;
  grid-template-columns: 176px minmax(0, 1fr) auto 40px;
  align-items: center;
  column-gap: 24px;
  flex: 1 1 0; /* 平均撐滿面板：5 列各 66；有「明天」分隔的頁 4 列各約 72，下面不留白（設計師 2026-10-28）。最後一頁只剩 1–2 列時最高 80 */
  min-height: 0;
  max-height: 80px;
  padding: 0 16px;
  border-radius: calc(var(--kiosk-radius-card) - 12px);
  cursor: pointer;
}
.kv-schedule__row + .kv-schedule__row::before {
  content: '';
  position: absolute;
  left: 16px;
  right: 16px;
  top: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.kv-schedule__time {
  font: 800 32px/1 var(--kiosk-font-display);
  color: var(--kiosk-text-primary);
}
.kv-schedule__film {
  font: 700 26px/1.2 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kv-schedule__row.is-camp .kv-schedule__film {
  color: var(--kiosk-camp);
}
.kv-schedule__tags {
  display: flex;
  gap: 8px;
}
.kv-schedule__tag {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 10px;
  border-radius: 6px;
  font: 600 17px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.28);
  white-space: nowrap;
}
.kv-schedule__row::after {
  content: '';
  justify-self: end;
  grid-column: 4;
  width: 14px;
  height: 14px;
  border-top: 3px solid var(--kiosk-text-secondary);
  border-right: 3px solid var(--kiosk-text-secondary);
  transform: rotate(45deg);
  margin-right: 6px;
}
/* 按下：亮底 + 2px 框，圓角跟外框同心；上下兩條分隔線藏掉，框不會壓到線 */
.kv-schedule__row.is-pressed {
  background: var(--kiosk-glass-tap);
  box-shadow: inset 0 0 0 2px var(--kiosk-line-pressed);
}
.kv-schedule__row.is-pressed::before,
.kv-schedule__row.is-pressed + .kv-schedule__row::before {
  display: none;
}
/* 置頂列（設計師 2026-10-27 選 A）：第 1 頁最上面固定放本片的下一場，靠底色 + 片名活動色辨識（不另外標「本檔活動」）（今天沒有就放明天第一場，時間上方疊「明天」），
   下面 4 列照開演時間排、不重複這一場。只在第 1 頁。 */
.kv-schedule__row--pin {
  background: linear-gradient(90deg, rgba(255, 176, 90, 0.14), rgba(255, 176, 90, 0) 70%);
}
.kv-schedule__row--pin::before,
.kv-schedule__row--pin + .kv-schedule__row::before {
  display: none; /* 置頂列自己有底色，下面不再畫線（滿版的線會從圓角底下露出來；設計師 2026-10-27） */
}
/* 置頂列放的是明天的場次：「明天 10:30」同一行、跟時間差不多大（設計師 2026-10-27：標在右邊的小標籤會被當成今晚 10:30，
   疊在上面的小字也太容易漏看）。時間欄因此 150 → 176 */
.kv-schedule__when {
  display: flex;
  align-items: baseline;
  gap: 8px;
  white-space: nowrap;
}
.kv-schedule__when > small {
  font: 900 26px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
}
.kv-schedule__when > .kv-schedule__time {
  font-size: 30px;
}
/* 明天的分隔（21:00 以後今天剩不到 4 場時，接著列明天上午）：白色淡淡的就好，不用活動色（設計師 2026-10-27） */
.kv-schedule__day {
  display: flex;
  align-items: center;
  gap: 16px;
  height: 40px;
  flex: none;
  padding: 0 16px;
  font: 700 20px/1 var(--kiosk-font-ui);
  letter-spacing: 0.06em;
  color: var(--kiosk-text-secondary);
}
/* 最後一頁列數不滿：接在最後一列後面收一句，讓剩下的空間看起來是「列完了」而不是「少了東西」 */
.kv-schedule__end {
  flex: none;
  display: flex;
  align-items: center;
  gap: 16px;
  height: 56px;
  padding: 0 16px;
  font: 500 20px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-tertiary, var(--kiosk-text-secondary));
}
.kv-schedule__end::before,
.kv-schedule__end::after {
  content: '';
  flex: 1;
  border-top: 1px dashed rgba(255, 255, 255, 0.14);
}
.kv-schedule__day::after {
  content: '';
  flex: 1;
  border-top: 1px solid rgba(255, 255, 255, 0.16);
}
.kv-schedule__foot {
  flex: none;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.kv-schedule__scope {
  font: 500 22px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-secondary);
}
.kv-schedule__pager {
  display: flex;
  align-items: center;
  gap: 16px;
}
.kv-schedule__dots {
  display: flex;
  gap: 8px;
}
.kv-schedule__dots i {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.25);
}
.kv-schedule__dots i.is-on {
  background: var(--kiosk-text-primary);
}
.kv-schedule__next {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  height: 56px;
  padding: 0 26px;
  border: 0;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-tap);
  box-shadow: inset 0 0 0 1.5px var(--kiosk-line-tap);
  font: 700 24px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
  cursor: pointer;
}
.kv-schedule__next::after {
  content: '→';
  font-size: 26px;
}
/* 上一頁（設計師 2026-10-27）：第 2 頁起才出現，放在頁點左邊；純文字、淡色、不搶「下一頁」，點擊高度一樣 56 */
.kv-schedule__prev {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 56px;
  padding: 0 12px;
  border: 0;
  background: none;
  font: 600 22px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-secondary);
  cursor: pointer;
}
.kv-schedule__prev[hidden] {
  display: none;
}
.kv-schedule__prev::before {
  content: '←';
  font-size: 22px;
}
.kv-schedule__prev.is-pressed {
  color: var(--kiosk-text-primary);
}
.kv-schedule__next.is-pressed {
  box-shadow: inset 0 0 0 2px var(--kiosk-line-pressed);
}
.kv-safe--schedule {
  height: 420px;
  align-items: stretch;
}

/* ============================================================ v4.3 · 語音模式的「← 首頁」（設計師 2026-10-30）
   開了對話之後觀眾不知道怎麼回首頁 → 語音模式也放觸控版那顆文字鍵（同 .kv-tnav__home 的語言），左下角、跟對話框同一列。
   對話框不往右讓：平常縮短到 760 置中（左邊剛好空出首頁鍵），聆聽 / 已送出時撐到 1152 蓋過首頁鍵（講話當下不會想回首頁），說完再縮回。
   首頁 P01b / TP01b 自己不放；觸控模式用 .kv-tnav 的回首頁、這顆藏掉。點了 = 回 P01b（session 內，不經 P01）。 */
.kv-home {
  position: absolute;
  left: var(--kiosk-margin);
  bottom: var(--kiosk-pill-bottom);
  height: var(--kiosk-pill-h);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 0 8px;
  font: 600 26px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
  cursor: pointer;
  z-index: 4;
  transition: opacity var(--kiosk-dur-chrome) var(--kiosk-ease);
}
.kv-home::before {
  content: '←';
  font-size: 28px;
}
.kv-home.is-pressed {
  color: var(--kiosk-text-primary);
}
.kv-screen--touch > .kv-home {
  display: none;
}
.kv-screen:has(> .kv-home) > .kv-pill {
  width: var(--kiosk-pill-w-rest);
  left: calc((var(--kiosk-center-w) - var(--kiosk-pill-w-rest)) / 2);
  transition:
    width 300ms var(--kiosk-ease),
    left 300ms var(--kiosk-ease),
    height 300ms var(--kiosk-ease),
    box-shadow 300ms var(--kiosk-ease),
    background 300ms var(--kiosk-ease);
}
.kv-screen:has(> .kv-home) > .kv-pill.kv-pill--listening,
.kv-screen:has(> .kv-home) > .kv-pill.kv-pill--sent {
  width: var(--kiosk-pill-w); /* 設計師 2026-10-30 晚：聆聽 / 已送出就回到 DS 標準寬（856、置中），不再撐到 1152 */
  left: calc((var(--kiosk-center-w) - var(--kiosk-pill-w)) / 2);
}
.kv-screen:has(> .kv-pill.kv-pill--listening) > .kv-home,
.kv-screen:has(> .kv-pill.kv-pill--sent) > .kv-home {
  opacity: 0;
  pointer-events: none;
}
/* 拍好了（review2）的法務小字本來在左下，有首頁鍵時往上讓（同觸控版的做法） */
.kv-screen--review2:has(> .kv-home) > .kv-hint.kv-hint--legal {
  bottom: calc(var(--kiosk-pill-bottom) + var(--kiosk-pill-h) + 16px);
}
/* 選版型 PICK（2026-11-05 設計師實測：這頁也收音，對話框放回來，原本 .kv-screen--no-pill 拿掉）：
   卡片區 296–600（304 高；卡片 padding 22、預覽 176 / --story-w 144），同意小字移到卡片下方（y 620–638），離對話框（672）34。
   觸控版（.kv-screen--touch，底部是 .kv-tnav）不受影響 */
.kv-screen:not(.kv-screen--touch) > .kv-safe.kv-pick {
  height: 304px;
}
.kv-screen:not(.kv-screen--touch) > .kv-pick .kv-pick-card {
  padding-top: 22px;
  padding-bottom: 22px;
}
.kv-screen:not(.kv-screen--touch) > .kv-pick .kv-pick-card__preview {
  width: 176px;
}
.kv-screen:not(.kv-screen--touch) > .kv-pick .kv-pick-card__preview > .kv-story {
  --story-w: 144px;
}
.kv-screen:not(.kv-screen--touch):has(> .kv-pick) > .kv-hint.kv-hint--legal {
  bottom: 162px;
}

/* ============================================================ v4.2 · 觸控模式（正式模式，設計師 2026-10-28）
   後台人工切換「語音 / 觸控」，下一個 session 生效。觸控模式跟語音一樣完整：視覺大方向相同，但**不放底部的 user 對話框**，
   底部那格換成導覽（.kv-tnav：← 回首頁 + 這頁相關的下一步），中間內容往下長（AI 1 行 432 / 2 行 360 / 3 行 288）。
   Kebbi 照樣說話（只是不收音）；頂列不放「暫停收音」（.kv-screen--touch 把收音膠囊藏掉）。
   導覽：首頁（P01b 觸控版）→ 每件事一頁 → 最多再深一層；查場次 = 選電影 → 那部片的場次（最後一頁，不放 QR）→ 活動好康卡 + QR。 */
.kv-screen--touch .kv-topbar .kv-mic {
  display: none;
}
.kv-screen--touch.kv-screen--one-line > .kv-safe {
  top: var(--kiosk-safe-top-1line);
  height: var(--kiosk-safe-h-touch-1line);
}
/* 首頁（TP01b 觸控版）：沒有對話框，拍照大卡與右欄四顆往下長。喚醒中（P01a）也不出「正在啟動」那顆彩框（設計師 2026-10-29：
   觸控模式從頭到尾不放對話框，等待提示就是火星 + 骨架） */
.kv-screen--start.kv-screen--touch > .kv-pill {
  display: none;
}
/* 觸控版 TE12 時間到：QR 放大置中（語音版 .kv-qr--xl 靠對話底排；觸控版內容區是 flex 撐滿，要自己置中、不拉寬） */
.kv-screen--touch .kv-qr--xl {
  flex: 0 0 auto;
  margin: auto;
}
.kv-screen--start.kv-screen--touch > .kv-cap-hero,
.kv-screen--start.kv-screen--touch > .kv-caps {
  height: var(--kiosk-touch-home-h);
}
.kv-screen--start.kv-screen--touch > .kv-caps {
  gap: 16px; /* 四顆往下長之後要留間距，不然會黏在一起（設計師 2026-10-28） */
}
.kv-screen--start.kv-screen--touch .kv-cap {
  height: auto;
  flex: 1;
}

/* 底部導覽：左「← 回首頁」（不顯眼的文字鈕），右 1–2 顆下一步（.kv-chip） */
.kv-tnav {
  position: absolute;
  left: var(--kiosk-margin);
  right: var(--kiosk-margin);
  bottom: var(--kiosk-pill-bottom);
  height: var(--kiosk-slot-chips);
  z-index: 4;
  display: flex;
  align-items: center;
  gap: 16px;
}
.kv-tnav__home {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 100%;
  padding: 0 8px;
  margin-right: auto;
  border: 0;
  background: none;
  font: 600 26px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
  cursor: pointer;
}
.kv-tnav__home::before {
  content: '←';
  font-size: 28px;
}
.kv-tnav__home.is-pressed {
  color: var(--kiosk-text-primary);
}
/* 往上一層（例：場次頁的「選別部片」）：跟「回首頁」同一種文字鈕、並排在左邊，右下角只留翻頁那一顆（設計師 2026-10-28：兩顆膠囊疊在右下角很重複） */
.kv-tnav__back {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 100%;
  padding: 0 8px 0 24px;
  margin-right: auto;
  border-left: 1px solid rgba(255, 255, 255, 0.18);
  font: 600 26px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
  cursor: pointer;
}
.kv-tnav__back::before {
  content: '‹';
  font-size: 34px;
  line-height: 0.8;
}
.kv-tnav__home:has(+ .kv-tnav__back) {
  margin-right: 8px;
}
.kv-tnav__back.is-pressed {
  color: var(--kiosk-text-primary);
}

/* 選電影（查場次第一頁，設計師 2026-10-28 第四版）：沒有 hover → 跟場次表一樣「上一頁 / 下一頁」翻；全部不放海報、統一排版（別部片拿不到海報）；
   一頁 4 張、**左右一排**的直卡：上面片名（最多三行）、下面「下一場」+ 大時間 + 版本，右上箭頭。本片固定第 1 頁第一張（暖色底 + 片名活動色）。 */
.kv-films {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  height: 100%;
}
.kv-films__grid {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-template-rows: minmax(0, 1fr);
  gap: 16px;
}
.kv-film {
  position: relative;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 12px;
  padding: 26px 24px 24px;
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-glass-info);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
  cursor: pointer;
  transition: transform var(--kiosk-dur-press) var(--kiosk-ease);
}
.kv-film::after {
  content: '';
  position: absolute;
  right: 24px;
  top: 32px;
  width: 13px;
  height: 13px;
  border-top: 3px solid var(--kiosk-text-secondary);
  border-right: 3px solid var(--kiosk-text-secondary);
  transform: rotate(45deg);
}
.kv-film.is-pressed {
  transform: scale(0.97);
  background: var(--kiosk-glass-tap);
  box-shadow: inset 0 0 0 2px var(--kiosk-line-pressed);
}
.kv-film--pin {
  background: linear-gradient(180deg, rgba(255, 176, 90, 0.18), rgba(255, 176, 90, 0.03)), var(--kiosk-glass-info);
}
.kv-film__title {
  padding-right: 28px;
  font: 900 32px/1.3 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.kv-film--pin .kv-film__title {
  color: var(--kiosk-camp);
}
.kv-film__meta {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.kv-film__next {
  display: flex;
  flex-direction: column;
  gap: 8px;
  white-space: nowrap;
  font: 500 20px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-secondary);
}
.kv-film__next b {
  font: 800 44px/1 var(--kiosk-font-display);
  color: var(--kiosk-text-primary);
}
.kv-film__meta .kv-schedule__tags {
  min-height: 30px; /* 沒有版本的片也留一行高，四張卡的時間才會對齊 */
}

/* 拍照：觸控模式的「取消」（站位 / 倒數時右上角）與預覽的「再拍一次」（底部導覽裡，300s 收尾模式後不放） */
.kv-cam-cancel {
  position: absolute;
  top: 64px; /* 跟右邊一樣離取景外框內緣 28（外框 28 + 邊 8 + 28；設計師 2026-10-28：原本 40 太貼上緣） */
  right: var(--kiosk-margin);
  z-index: 9;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 60px;
  padding: 0 26px;
  border: 0;
  border-radius: var(--kiosk-radius-pill);
  background: rgba(10, 10, 10, 0.55);
  box-shadow: inset 0 0 0 1.5px var(--kiosk-line-tap);
  font: 600 24px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
  cursor: pointer;
}
.kv-cam-cancel::before {
  content: '✕';
  font-size: 22px;
}
.kv-cam-cancel.is-pressed {
  box-shadow: inset 0 0 0 2px var(--kiosk-line-pressed);
}
/* 觸控模式選版型：內容區比語音短（底部有導覽，360 高）→ 卡片上下 padding 收到 28、限動框預覽縮到 160 寬（284 高），不會凸出卡片（設計師 2026-10-28：破版） */
.kv-screen--touch .kv-pick-card {
  padding-top: 28px;
  padding-bottom: 28px;
}
.kv-screen--touch .kv-pick-card__preview {
  width: 196px;
}
.kv-screen--touch .kv-pick-card__preview > .kv-story {
  --story-w: 160px;
}
/* 觸控模式不收音：相機畫面底部「說「等一下」可以暫停」不出 */
.kv-screen--touch.kv-screen--camera > .kv-hint {
  display: none;
}
/* v4.3 ④ P06 = session 最後一步（設計師 2026-10-30）：不收音；「再拍一次 / 再問一件事」兩顆 chips 放在左欄 AI 句下面，
   跟對話畫面的 chips 同一個位置（left 56 對齊標題、top = safe-top 296）；回首頁照舊左下（語音 .kv-home、觸控 .kv-tnav）。
   點「再問一件事」對話框升起（is-dim）時 chips 收掉；300s 收尾模式不放「再拍一次」 */
.kv-screen--review2 > .kv-chips {
  position: absolute;
  left: 56px;
  top: var(--kiosk-safe-top);
  z-index: 2;
}
.kv-screen--review2.kv-screen--touch > .kv-chips { /* 觸控版的 chips 平常在底部橫排；P06 這兩顆跟語音版一樣放標題下 */
  top: var(--kiosk-safe-top);
  bottom: auto;
  left: 56px;
  width: auto;
  height: auto;
  flex-direction: column;
  align-items: flex-start;
}
.kv-screen--review2.is-dim > .kv-chips {
  display: none;
}
.kv-screen--review2.is-wrapup .kv-chips [data-act='retake'],
.kv-screen--touch.is-wrapup .kv-tnav [data-act='retake'] {
  display: none;
}

/* 新片資訊版型（v4.2，兩種模式共用）：**不是可以切換的分頁**，腦依這次回答的內容選一個版型、跟著回答一起出（設計師 2026-10-28）。
   四種：--plot 劇情（海報 + 一段簡介）· --cast 角色群像（1–3 位）· --character 單一角色（大劇照 + 名字 + 身分 + 兩行介紹）· --facts 幕後 / 事實（3 則）。 */
.kv-info {
  flex: 1;
  min-width: 0;
  display: flex;
  gap: 32px;
  padding: 28px;
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-glass-info);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
}
.kv-info__label {
  font: var(--kiosk-type-card-label);
  color: var(--kiosk-text-secondary);
}
/* 劇情：海報 + 一段簡介 */
.kv-info--plot > img {
  flex: none;
  height: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: 16px;
}
.kv-info__text {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 16px;
  min-width: 0;
}
.kv-info__lead {
  font: 700 30px/1.5 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
}
/* 角色：1–3 位，劇照 + 名字 + 一句 */
.kv-info--cast {
  gap: 24px;
}
.kv-cast {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.kv-cast > img {
  flex: 1;
  min-height: 0;
  width: 100%;
  object-fit: cover;
  border-radius: 16px;
}
.kv-cast__name {
  font: 900 30px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
}
.kv-cast__line {
  font: 500 20px/1.35 var(--kiosk-font-ui);
  color: var(--kiosk-text-secondary);
}
/* 幕後（設計師 2026-10-28 第三版：第二版太滿 → 不放背景、不用活動色，只用大字小字排）：
   左邊一個大數字「65th」當主角，右邊兩則事實（小標 + 大字 + 小字）；全部白 / 灰兩階，靠字級拉層次。 */
.kv-info--facts {
  gap: 0;
  padding: 0;
}
.kv-facts__hero {
  flex: 0 0 46%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 8px;
  padding: 0 40px;
}
.kv-facts__eyebrow {
  font: 600 16px/1 var(--kiosk-font-mono);
  letter-spacing: 0.12em;
  color: var(--kiosk-text-secondary);
}
.kv-facts__num {
  font: 800 160px/0.9 var(--kiosk-font-display);
  letter-spacing: -0.04em;
  color: var(--kiosk-text-primary);
}
.kv-facts__num small {
  font-size: 48px;
  letter-spacing: 0;
  margin-left: 6px;
  color: var(--kiosk-text-primary);
}
.kv-facts__cap {
  font: 700 26px/1.3 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
}
.kv-facts__list {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 28px;
  padding: 0 40px;
}
.kv-facts__item {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.kv-facts__item b {
  font: 900 34px/1.2 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
}
.kv-facts__item > span:last-child {
  font: 500 20px/1.3 var(--kiosk-font-ui);
  color: var(--kiosk-text-secondary);
}
/* 新片資訊 · 單一角色（腦回答「女王是誰」這類問題時） */
.kv-info--character {
  gap: 32px;
}
.kv-info--character > img {
  flex: 0 0 52%;
  height: 100%;
  object-fit: cover;
  border-radius: 16px;
}
.kv-info--character .kv-info__text {
  gap: 14px;
}
.kv-info__name {
  font: 900 48px/1.1 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
}
.kv-info__role {
  font: 600 22px/1 var(--kiosk-font-ui);
  color: var(--kiosk-camp);
}
.kv-info__body {
  font: 500 24px/1.55 var(--kiosk-font-ui);
  color: var(--kiosk-text-muted-light);
}

/* ============================================================ 2026-11-05 活動時間軸版（預覽中：網址帶 ?date= 才會掛上，timeline.html 切日期看）
   無活動期（同框禮結束後–12/10，js/event.js 在 <html> 掛 .kv-ev-none）：活動卡與它的 QR 不出現（語音問到只回一句「活動已結束」）；
   首頁右欄少「活動好康」→ 三顆，高度 86 → 120、間距維持 16（骨架跟著換）；時間到沒拍照（E12）不給 QR（.is-noqr）。 */
.kv-ev-none [data-role="eventCard"],
.kv-ev-none .is-event .kv-qr,
.is-noqr .kv-qr {
  display: none !important;
}
.kv-caps--3 .kv-cap {
  height: 120px;
  /* 2026-11-05 設計師：變大圓角後文字與箭頭要再內縮——箭頭圓（58）跟按鈕右端圓弧同心：右內距 = 半徑 60 − 29 = 31；文字左內距跟著放大到 48 */
  padding: 0 31px 0 48px;
}
/* 觸控首頁三顆是 flex 撐滿（約 149 高、半徑約 75）：右內距 75 − 29 ≈ 45、左 56 */
.kv-screen--start.kv-screen--touch > .kv-caps--3 .kv-cap {
  padding: 0 45px 0 56px;
}
.kv-skel--caps3 [data-skel="col"] {
  --h: 120px !important;
  --r: 60px !important;
}
.kv-skel--caps3 [data-skel="col"]:nth-child(3) {
  --y: 368px !important;
}
.kv-skel--caps3 [data-skel="col"]:nth-child(4) {
  --y: 504px !important;
}
.kv-skel--caps3 [data-skel="col"]:nth-child(5) {
  display: none;
}
/* Side 機器人能幹嘛 02：同框期只剩斗篷那張券，放在兩張券原本的中間（同預購期只剩海報券的 --solo） */
.kv-promo-gift--b.kv-promo-gift--solo {
  top: 180px;
  rotate: 1.5deg;
}

/* ---------- 只剩一個活動時的活動卡（2026-11-05 時間軸版：預購期只有海報、同框期只有斗篷）
   設計師：維持原本版面、不加資訊（之後有改才不用兩邊一起改），只把圖放大——斗篷正反兩面都放、兩張海報拆開並排不疊。 */
.kv-event__item--solo {
  gap: 36px;
  padding-left: 8px;
}
.kv-event__cloaks {
  position: relative;
  flex: none;
  width: 340px;
  height: 228px;
}
.kv-event__cloaks img {
  position: absolute;
  top: 4px;
  height: 220px;
  object-fit: contain;
  filter: drop-shadow(0 10px 18px rgba(0, 0, 0, 0.45));
}
.kv-event__cloaks img:first-child {
  left: 0;
  width: 180px;
  rotate: -5deg;
}
.kv-event__cloaks img:last-child {
  left: 156px;
  width: 184px;
  rotate: 4deg;
}
.kv-event__item--solo > .kv-event__posters {
  width: 306px;
  height: 228px;
}
.kv-event__item--solo > .kv-event__posters img {
  top: 6px;
  width: 140px;
  height: 210px;
}
.kv-event__item--solo > .kv-event__posters img:first-child {
  left: 4px;
  rotate: -4deg;
}
.kv-event__item--solo > .kv-event__posters img:last-child {
  left: 162px;
  top: 10px;
  rotate: 3deg;
}

/* ============================================================================
   spinJoy · Center 商品元件 v2（Claude Design 定稿 2026-11-09，設計師 review 過；交接包 design-briefs/product-cards-2026-11-09/handoff-v2/）
   ----------------------------------------------------------------------------
   取代 2026-11-09 第一版（.kv-prod / .kv-ask / .kv-bundle / .kv-compare 全部換新結構）。只搬元件，畫面骨架（.kv-screen / .kv-topbar /
   .kv-transcript / .kv-safe / .kv-pill / .kv-actions / .kv-btn / .kv-home）用 DS 既有的；交接的 .kv-top / .kv-ai / .kv-safe--1line 不進來。
   改名：交接的 .kv-move（帶位中）跟 DS 的 .kv-move 撞名 → .kv-go。
   規則（交接 README）：只用 --kiosk-* token；amber 只給優惠；Grow 一屏最多 2 處；勾選鈕看起來 56、可點 64；reset 用 :where() 不搶權重。
   ============================================================================ */

/* 交接的元件用 <button>（.kv-ask / .kv-entry / .kv-prod__check / .kv-compare__col）：歸零瀏覽器預設，權重用 :where() 壓到 0 */
:where(.kv-screen) :where(button) { font: inherit; color: inherit; border: 0; padding: 0; margin: 0; background: none; cursor: pointer; text-align: inherit; }
:where(.kv-screen) :where(h1, h2, h3, p) { margin: 0; }

/* 主 CTA 裡的數字膠囊（C01「Compare 2」） */
.kv-btn__count {
  min-width: 44px; height: 44px; padding: 0 12px; margin-left: 16px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-text-primary); color: var(--kiosk-surface-base);
  font: 800 22px/1 var(--kiosk-font-display);
}
/* 回列表鍵（C02）：設計師 review 決定不要框線、只留玻璃底（DS 的 .kv-home 是純文字 + 箭頭，這裡加底） */
.kv-screen--dialog > .kv-home {
  padding: 0 24px 0 18px;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-pill);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  font: var(--kiosk-type-cta);
  color: var(--kiosk-text-primary);
}
.kv-screen--dialog:has(> .kv-home) > .kv-pill:not(.kv-pill--listening):not(.kv-pill--sent) {
  left: 296px; /* 交接 .kv-pill--rest：回列表鍵有底之後比較寬，對話框從 296 起（DS 原本置中 260 會疊到） */
}

/* ---------------------------------------------------------------- 標籤 */
.kv-tag {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 32px;
  padding: 0 12px;
  border-radius: var(--kiosk-radius-tag);
  font: 700 16px/1 var(--kiosk-font-ui);
  white-space: nowrap;
}
.kv-tag--rank { background: var(--kiosk-overlay-pill); color: var(--kiosk-text-muted-light); }
.kv-tag--rank b { font: 800 16px/1 var(--kiosk-font-display); color: var(--kiosk-text-primary); }
.kv-tag--deal { background: var(--kiosk-accent-amber); color: var(--kiosk-surface-base); }
.kv-tag--pick { background: var(--kiosk-text-primary); color: var(--kiosk-surface-base); }
.kv-tag__spark { width: 10px; height: 10px; border-radius: 50%; background: var(--kiosk-grow); flex: none; }

/* ---------------------------------------------------------------- 商品卡 .kv-prod
   圖井（排名左上、優惠左下、勾選右下）· 名稱兩行 · 價格列。高度吃滿內容區 */
.kv-prod {
  position: relative;
  min-width: 0;
  min-height: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 14px 18px;
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-glass-info);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
  transition: transform var(--kiosk-dur-press) var(--kiosk-ease), background var(--kiosk-dur-press) var(--kiosk-ease), box-shadow var(--kiosk-dur-press) var(--kiosk-ease), opacity var(--kiosk-dur-fade) var(--kiosk-ease);
}
.kv-prod__img {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 44px 8px 8px;
  border-radius: 20px;
  background: rgba(255, 255, 255, 0.06);
}
.kv-prod__img > img { height: 100%; max-width: 100%; object-fit: contain; }
.kv-prod__img > .kv-tag--rank, .kv-prod__img > .kv-tag--pick { position: absolute; left: 10px; top: 10px; }
.kv-prod__img > .kv-tag--deal { position: absolute; left: 10px; bottom: 10px; }
.kv-prod__body { display: flex; flex-direction: column; gap: 8px; padding: 0 6px; }
.kv-prod__name {
  font: 700 22px/1.25 var(--kiosk-font-ui);
  height: 55px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.kv-prod__row { display: flex; align-items: baseline; gap: 10px; }
.kv-prod__price { font: 800 30px/1 var(--kiosk-font-display); }
.kv-prod__was { font: 500 18px/1 var(--kiosk-font-ui); color: var(--kiosk-text-secondary); text-decoration: line-through; }
.kv-prod__size { margin-left: auto; font: 500 18px/1 var(--kiosk-font-ui); color: var(--kiosk-text-secondary); white-space: nowrap; }

/* 勾選比較：看起來 56、可點 64 */
.kv-prod__check {
  position: absolute;
  right: 10px;
  bottom: 10px;
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--kiosk-overlay-media);
  box-shadow: inset 0 0 0 2px var(--kiosk-line-tap);
  color: transparent;
}
.kv-prod__check::after { content: ''; position: absolute; inset: -4px; border-radius: 50%; }
.kv-prod__check svg { width: 28px; height: 28px; }

/* 勾選圓平常不出現（設計師 2026-11-09：空的 radio 看不出用途）：點整張卡 = 勾選，勾了才出白框 + ✓；可點範圍仍是整張卡 */
.kv-prod__check { opacity: 0; transition: opacity var(--kiosk-dur-press) var(--kiosk-ease); }
.kv-prod.is-checked .kv-prod__check, .kv-prod.is-selected .kv-prod__check { opacity: 1; }
.kv-compare__col > .kv-prod__check { opacity: 0; }
.kv-compare__col.is-selected > .kv-prod__check { opacity: 1; }

/* 狀態 */
.kv-prod.is-pressed { transform: scale(0.97); background: rgba(255, 255, 255, 0.12); box-shadow: inset 0 0 0 2px var(--kiosk-line-pressed), var(--kiosk-shadow-card); }
.kv-prod.is-checked { box-shadow: inset 0 0 0 2px var(--kiosk-line-pressed); }
.kv-prod.is-checked .kv-prod__check { background: var(--kiosk-text-primary); color: var(--kiosk-surface-base); box-shadow: none; }
.kv-prod.is-dimmed { opacity: 0.4; }
/* Top pick / 已選：Grow 3px 環 + 實色底（漸層環要 padding-box，不能疊玻璃） */
.kv-prod--top,
.kv-prod.is-selected {
  border: var(--kiosk-grow-ring) solid transparent;
  background: linear-gradient(var(--kiosk-surface-raised), var(--kiosk-surface-raised)) padding-box, var(--kiosk-grow) border-box;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: var(--kiosk-glow-card);
  padding: 11px 11px 15px;
}
.kv-prod.is-selected .kv-prod__check { background: var(--kiosk-text-primary); color: var(--kiosk-surface-base); box-shadow: none; }
.kv-prod--top.is-checked .kv-prod__check { background: var(--kiosk-text-primary); color: var(--kiosk-surface-base); box-shadow: none; }

/* 寬卡（W06s 拒絕加購後的抵達：走道牌旁只有一款，橫排撐滿；設計師 2026-11-09） */
.kv-prod--wide { flex: 1; flex-direction: row; align-items: stretch; gap: 24px; padding: 14px; }
.kv-prod--wide .kv-prod__img { flex: none; width: 320px; height: 100%; }
.kv-prod--wide .kv-prod__body { flex: 1; justify-content: center; gap: 14px; padding: 0 16px 0 4px; }
.kv-prod--wide .kv-prod__name { height: auto; font: 700 36px/1.2 var(--kiosk-font-ui); }
.kv-prod--wide .kv-prod__price { font-size: 44px; }
.kv-prod--wide .kv-prod__size { font-size: 22px; }
.kv-prod--wide .kv-prod__note { font: 500 22px/1.35 var(--kiosk-font-ui); color: var(--kiosk-text-muted-light); }
.kv-prod--top.kv-prod--wide { padding: 11px; }

/* 迷你卡（W04 壓暗的其他候選） */
.kv-prod--mini { flex-direction: row; align-items: center; gap: 12px; padding: 10px 14px 10px 10px; border-radius: 24px; }
.kv-prod--mini .kv-prod__img { flex: none; width: 64px; height: 100%; padding: 6px; border-radius: 16px; }
.kv-prod--mini .kv-prod__body { min-width: 0; padding: 0; gap: 6px; }
.kv-prod--mini .kv-prod__name { height: auto; font: 500 16px/1.2 var(--kiosk-font-ui); -webkit-line-clamp: 1; color: var(--kiosk-text-muted-light); }
.kv-prod--mini .kv-prod__price { font-size: 22px; }

/* ---------------------------------------------------------------- Spinjoy 方案卡（S01 / S02，第二階段支線，2026-11-09）
   同商品卡的玻璃卡 + Top pick Grow 環；內容是方案：eyebrow、名稱、每日價（Unbounded）、月價、兩三行內容 */
.kv-plan {
  position: relative;
  min-width: 0;
  min-height: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 24px 24px 22px;
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-glass-info);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
  transition: opacity var(--kiosk-dur-fade) var(--kiosk-ease);
}
.kv-plan__eyebrow { font: 500 16px/1 var(--kiosk-font-mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--kiosk-text-secondary); }
.kv-plan__name { font: 700 28px/1.2 var(--kiosk-font-ui); min-height: 68px; }
.kv-plan__price { display: flex; align-items: baseline; gap: 6px; font: 800 44px/1 var(--kiosk-font-display); }
.kv-plan__price small { font: 500 20px/1 var(--kiosk-font-ui); color: var(--kiosk-text-secondary); }
.kv-plan__price--text { font: 700 26px/1.2 var(--kiosk-font-ui); min-height: 44px; } /* Day Pass 沒標價 */
.kv-plan__mo { font: 500 18px/1 var(--kiosk-font-ui); color: var(--kiosk-text-secondary); }
.kv-plan__list { margin: auto 0 0; padding: 12px 0 0; border-top: 1px solid var(--kiosk-line-info); display: flex; flex-direction: column; gap: 6px; font: 500 18px/1.3 var(--kiosk-font-ui); color: var(--kiosk-text-muted-light); list-style: none; }
.kv-plan__list li::before { content: '· '; color: var(--kiosk-text-secondary); }
.kv-plan > .kv-tag { position: absolute; right: 16px; top: 16px; }
.kv-plan--top {
  border: var(--kiosk-grow-ring) solid transparent;
  background: linear-gradient(var(--kiosk-surface-raised), var(--kiosk-surface-raised)) padding-box, var(--kiosk-grow) border-box;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: var(--kiosk-glow-card);
  padding: 21px 21px 19px;
}
.kv-plan.is-dimmed { opacity: 0.4; }
/* 洗劑三選一（S03）：商品卡沒有瓶子，圖井放文字佔位 */
.kv-prod__img > .kv-ph { width: 100%; height: 100%; font: 600 20px/1.3 var(--kiosk-font-ui); color: var(--kiosk-text-muted-light); border-radius: 14px; }
/* S04：QR 卡旁的方案摘要 */
.kv-signup { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 10px; padding: 28px 32px; border-radius: var(--kiosk-radius-card); background: var(--kiosk-glass-info); backdrop-filter: var(--kiosk-glass-blur); -webkit-backdrop-filter: var(--kiosk-glass-blur); box-shadow: inset 0 0 0 1px var(--kiosk-line-info); }
.kv-signup__eyebrow { font: 600 18px/1 var(--kiosk-font-mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--kiosk-accent-amber); }
.kv-signup__title { font: 700 36px/1.2 var(--kiosk-font-ui); }
.kv-signup__sub { font: 500 22px/1.35 var(--kiosk-font-ui); color: var(--kiosk-text-muted-light); }
.kv-signup__steps { margin-top: 8px; padding-top: 12px; border-top: 1px solid var(--kiosk-line-info); font: 500 20px/1.4 var(--kiosk-font-ui); color: var(--kiosk-text-secondary); }

/* ---------------------------------------------------------------- 貨架 */
.kv-shelf { display: flex; gap: var(--kiosk-card-gap); width: 100%; height: 100%; }
.kv-shelf__aside { flex: none; width: 368px; display: flex; flex-direction: column; gap: 12px; }
.kv-shelf__aside--mini { width: 208px; }
.kv-shelf__aside--mini > .kv-prod { flex: 1; height: auto; }
.kv-products { flex: 1; min-width: 0; display: grid; grid-template-columns: repeat(var(--cols, 4), minmax(0, 1fr)); gap: var(--kiosk-card-gap); height: 100%; }
.kv-products--3 { --cols: 3; }
.kv-products--4 { --cols: 4; }

/* ---------------------------------------------------------------- 追問欄（W02 右欄） */
.kv-ask {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 14px 0 32px;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-tap);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1.5px var(--kiosk-line-tap);
  font: var(--kiosk-type-action);
  color: var(--kiosk-text-primary);
  text-align: left;
  transition: transform var(--kiosk-dur-press) var(--kiosk-ease), background var(--kiosk-dur-press) var(--kiosk-ease);
}
.kv-ask__label { flex: 1; }
.kv-ask__arrow {
  width: var(--kiosk-check, 36px);
  width: 58px; height: 58px; flex: none;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px var(--kiosk-line-tap);
}
.kv-ask__arrow svg { width: 28px; height: 28px; }
.kv-ask.is-pressed { transform: scale(0.97); box-shadow: inset 0 0 0 2px var(--kiosk-line-pressed); }
.kv-ask.is-on { background: var(--kiosk-text-primary); color: var(--kiosk-surface-base); box-shadow: var(--kiosk-glow-cta); }
.kv-ask.is-on .kv-ask__arrow { background: var(--kiosk-surface-base); color: var(--kiosk-text-primary); box-shadow: none; }
.kv-ask.is-off { opacity: 0.4; }

/* ---------------------------------------------------------------- 開場入口（W01 / W07） */
.kv-entry {
  position: relative;
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 36px 36px 32px;
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-glass-tap);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1.5px var(--kiosk-line-tap), var(--kiosk-shadow-card);
  text-align: left;
}
.kv-entry__icon { flex: none; width: 96px; height: 96px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: rgba(255, 255, 255, 0.10); } /* flex: none：卡片是 column flex，內容撐滿 316 時圓底會被壓扁（2026-11-09） */
.kv-entry__icon svg { width: 48px; height: 48px; }
.kv-entry__eyebrow { font: 500 18px/1 var(--kiosk-font-mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--kiosk-text-secondary); }
.kv-entry__eyebrow--deal { color: var(--kiosk-accent-amber); }
.kv-entry__title { font: var(--kiosk-type-card-value); margin-top: 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kv-entry__sub { font: 400 22px/1.4 var(--kiosk-font-ui); color: var(--kiosk-text-muted-light); margin-top: 6px; }
.kv-entry__go { /* 設計師 2026-11-09：箭頭改到右上角，標題可以長一點、不用讓位 */
  position: absolute; right: 32px; top: 36px;
  width: 72px; height: 72px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--kiosk-text-primary); color: var(--kiosk-surface-base);
}
.kv-entry__go svg { width: 32px; height: 32px; }

/* ---------------------------------------------------------------- Pair & save（W04 ★）
   一張大卡 = 一組：兩支瓶子站在同一條 Grow 貨架線上（「一起拿」），
   右側把便宜講白（40% off、兩件合計、省多少）。其餘候選縮成右邊的壓暗迷你卡。 */
.kv-bundle {
  flex: 1;
  min-width: 0;
  display: flex;
  gap: 16px;
  padding: 14px;
  border: var(--kiosk-grow-ring) solid transparent;
  border-radius: var(--kiosk-radius-card);
  background: linear-gradient(var(--kiosk-surface-raised), var(--kiosk-surface-raised)) padding-box, var(--kiosk-grow) border-box;
  box-shadow: var(--kiosk-glow-card);
}
.kv-bundle__pair { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 12px; }
.kv-bundle__stage {
  position: relative;
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 64px minmax(0, 1fr);
  align-items: end;
  padding: 16px 24px 0;
  border-radius: 20px;
  background: rgba(255, 255, 255, 0.06);
}
.kv-bundle__bottle { height: 100%; min-height: 0; display: flex; align-items: flex-end; justify-content: center; padding-bottom: 16px; }
.kv-bundle__bottle > img { height: 100%; max-width: 100%; object-fit: contain; }
.kv-bundle__plus {
  align-self: center;
  width: 56px; height: 56px; margin-bottom: 16px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--kiosk-text-primary);
  color: var(--kiosk-surface-base);
}
.kv-bundle__plus svg { width: 28px; height: 28px; }
.kv-bundle__stage > .kv-tag { position: absolute; top: 12px; }
.kv-bundle__stage > .kv-tag--a { left: 12px; }
.kv-bundle__stage > .kv-tag--b { right: 12px; }
.kv-bundle__names { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; padding: 0 10px; }
.kv-bundle__item { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.kv-bundle__item .kv-prod__name { height: auto; -webkit-line-clamp: 1; }
.kv-bundle__item .kv-prod__price--deal { color: var(--kiosk-accent-amber); }

.kv-bundle__save { /* 設計師 2026-11-09：優惠數字更大、合計壓到底跟左邊兩個價格同一列 */
  flex: none;
  width: 400px; /* Unbounded 很寬：「40% OFF」在 84px 約 310px，316 會破版 */
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: 4px;
  padding: 18px 24px 12px;
  border-radius: 20px;
  background: rgba(255, 255, 255, 0.06);
}
.kv-bundle__eyebrow { font: 600 18px/1 var(--kiosk-font-mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--kiosk-accent-amber); }
.kv-bundle__pct { display: flex; align-items: baseline; gap: 10px; color: var(--kiosk-accent-amber); white-space: nowrap; margin-top: 6px; }
.kv-bundle__pct > span[lang] { display: flex; align-items: baseline; gap: 10px; }
.kv-bundle__pct b { font: var(--kiosk-type-card-num); letter-spacing: -0.03em; }
.kv-bundle__pct span { font: 800 40px/1 var(--kiosk-font-display); }
:root[data-lang="zh"] .kv-bundle__pct b { font-size: 112px; } /* 「6 折」字少，放大到跟 40% OFF 一樣有份量 */
:root[data-lang="zh"] .kv-bundle__pct span { font-size: 56px; }
.kv-bundle__note { font: 500 22px/1.3 var(--kiosk-font-ui); color: var(--kiosk-text-muted-light); margin-top: 6px; }
.kv-bundle__total {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin-top: auto; padding-top: 12px;
  border-top: 1px solid var(--kiosk-line-info);
  font: 500 20px/1 var(--kiosk-font-ui);
  color: var(--kiosk-text-secondary);
}
.kv-bundle__total b { font: 800 34px/1 var(--kiosk-font-display); color: var(--kiosk-text-primary); }
.kv-bundle__total s { color: var(--kiosk-text-secondary); }

/* 抵達（W06a）：同一組，拿掉優惠欄、換成走道牌 */
.kv-bundle--found { box-shadow: none; }
.kv-aisle {
  flex: none;
  width: 316px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 8px;
  padding: 28px 32px;
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-glass-info);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
}
.kv-aisle__eyebrow { font: 500 18px/1 var(--kiosk-font-mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--kiosk-text-secondary); }
.kv-aisle__name { font: 600 30px/1 var(--kiosk-font-ui); margin-top: 8px; }
.kv-aisle__code { font: var(--kiosk-type-card-num); }
.kv-aisle__note { font: 500 20px/1.35 var(--kiosk-font-ui); color: var(--kiosk-text-muted-light); margin-top: 10px; }
.kv-aisle__code--text { font-size: 44px; line-height: 1.05; white-space: normal; } /* 文字目的地（Front entrance）：84px 會破 316 的牌子，縮到 44、准換行 */
.kv-aisle__note b { color: var(--kiosk-accent-amber); font-weight: 700; }

/* ---------------------------------------------------------------- 帶位中（W06 · AMBIENT）· 交接叫 .kv-move，跟 DS 既有的 .kv-move（上一案帶路大字）撞名，這裡改叫 .kv-go */
.kv-go { position: absolute; left: var(--kiosk-margin); right: var(--kiosk-margin); top: 200px; display: flex; flex-direction: column; gap: 28px; }
.kv-go__title { font: var(--kiosk-type-hero-lg); letter-spacing: -0.01em; }
.kv-go__line { width: 320px; height: 3px; border-radius: 3px; background: var(--kiosk-grow); }
.kv-go__route { display: flex; align-items: center; gap: 20px; font: var(--kiosk-type-hero-sub); color: var(--kiosk-text-muted-light); }
.kv-go__aisle {
  display: inline-flex; align-items: center; gap: 14px;
  height: 72px; padding: 0 32px;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-pill);
  box-shadow: inset 0 0 0 1.5px var(--kiosk-line-tap);
  font: 700 28px/1 var(--kiosk-font-ui); color: var(--kiosk-text-primary);
}
.kv-go__aisle b { font: 800 34px/1 var(--kiosk-font-display); }
.kv-go__list {
  position: absolute; left: var(--kiosk-margin); bottom: 64px;
  display: flex; align-items: center; gap: 20px;
  padding: 14px 28px 14px 14px;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-info);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
}
.kv-go__thumbs { display: flex; }
.kv-go__thumbs img { width: 56px; height: 72px; object-fit: contain; padding: 4px; border-radius: 16px; background: rgba(255, 255, 255, 0.08); }
.kv-go__thumbs img + img { margin-left: 8px; }
.kv-go__list-label { font: 500 18px/1 var(--kiosk-font-mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--kiosk-text-secondary); }
.kv-go__list-name { font: 700 24px/1.2 var(--kiosk-font-ui); margin-top: 8px; }

/* ---------------------------------------------------------------- 比較（C02） */
.kv-compare { display: grid; grid-template-columns: 148px repeat(2, minmax(0, 1fr)); gap: 0 var(--kiosk-card-gap); width: 100%; height: 100%; }
.kv-compare__labels, .kv-compare__col { display: grid; grid-template-rows: 92px repeat(4, minmax(0, 1fr)); }
.kv-compare__labels { padding: 14px 0; }
.kv-compare__labels > span { display: flex; align-items: center; font: 500 20px/1 var(--kiosk-font-ui); color: var(--kiosk-text-secondary); }
.kv-compare__col {
  position: relative;
  padding: 14px 24px;
  border-radius: var(--kiosk-radius-card);
  background: var(--kiosk-glass-info);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1px var(--kiosk-line-info);
  text-align: left;
  transition: transform var(--kiosk-dur-press) var(--kiosk-ease), box-shadow var(--kiosk-dur-press) var(--kiosk-ease), opacity var(--kiosk-dur-fade) var(--kiosk-ease);
}
.kv-compare__head { display: flex; align-items: center; gap: 16px; padding-right: 72px; }
.kv-compare__head > img { width: 56px; height: 76px; object-fit: contain; flex: none; }
.kv-compare__name { font: 700 24px/1.25 var(--kiosk-font-ui); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.kv-compare__col > .kv-prod__check { top: 26px; bottom: auto; right: 20px; }
.kv-compare__cell { display: flex; align-items: center; gap: 12px; border-top: 1px solid var(--kiosk-line-info); font: 500 24px/1.2 var(--kiosk-font-ui); }
.kv-compare__cell > b { font: 800 28px/1 var(--kiosk-font-display); }
.kv-compare__cell--none { color: var(--kiosk-text-secondary); }
.kv-compare__col.is-pressed { transform: scale(0.98); box-shadow: inset 0 0 0 2px var(--kiosk-line-pressed); }
.kv-compare__col.is-dimmed { opacity: 0.4; }
.kv-compare__col.is-selected {
  border: var(--kiosk-grow-ring) solid transparent;
  background: linear-gradient(var(--kiosk-surface-raised), var(--kiosk-surface-raised)) padding-box, var(--kiosk-grow) border-box;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: var(--kiosk-glow-card);
  padding: 11px 21px;
}
.kv-compare__col.is-selected > .kv-prod__check { top: 23px; right: 17px; background: var(--kiosk-text-primary); color: var(--kiosk-surface-base); box-shadow: none; }


/* ============================================================================
   spinJoy · 待機（W00）與結束（W08）提案（2026-11-09）
   簡報沒定義這兩張。待機沿用 DS 的 .kv-screen--start（is-idle：大標 + 底部「點一下」提示 + 火星），只補英文副標與本週優惠列；
   結束用置中大字 + 可選的「你選的 · 走道」回顧條。品牌（Walmart / Vyin / Spinjoy）待定，先用 Vyin AI 字標。
   ============================================================================ */
/* 上一案 v4.2 把待命大標拿掉（.kv-screen--start > .kv-welcome 是 display:none）；spinJoy 的待機要有大標，用 --w00 開回來。頂列照 DS：待命不放 */
.kv-screen--start.kv-screen--w00 > .kv-welcome {
  display: flex;
}
.kv-welcome__sub {
  font: var(--kiosk-type-hero-sub);
  color: var(--kiosk-text-muted-light);
  text-shadow: var(--kiosk-text-shadow-media);
  max-width: 980px;
}
/* 待機只剩兩段字（設計師 2026-11-09）：大標 + 副標整組往下移到畫面中央，不貼著上緣 */
.kv-screen--w00 > .kv-welcome { top: 0; bottom: 0; justify-content: center; gap: 28px; }
/* 待機 B：本週優惠三張放中間（y 300–600），點一張 = 說了那一款 */
.kv-standby-deals {
  position: absolute;
  left: var(--kiosk-margin);
  top: 300px;
  width: var(--kiosk-ai-w);
  height: 300px;
  z-index: 2;
}
.kv-standby-deals > .kv-products {
  --cols: 3;
}
/* 結束：置中大字 + 副標 */
.kv-bye {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  text-align: center;
  z-index: 2;
}
.kv-bye__title {
  font: var(--kiosk-type-hero-xl);
  color: var(--kiosk-text-primary);
  text-shadow: var(--kiosk-text-shadow-media);
  white-space: nowrap;
}
.kv-bye__sub {
  font: var(--kiosk-type-hero-sub);
  color: var(--kiosk-text-muted-light);
}
/* 結束 B：回顧條——你選的那款 + 走道，玻璃膠囊 */
.kv-bye__recap {
  margin-top: 28px;
  display: inline-flex;
  align-items: center;
  gap: 20px;
  padding: 14px 32px 14px 14px;
  border-radius: var(--kiosk-radius-pill);
  background: var(--kiosk-glass-pill);
  backdrop-filter: var(--kiosk-glass-blur);
  -webkit-backdrop-filter: var(--kiosk-glass-blur);
  box-shadow: inset 0 0 0 1.5px var(--kiosk-line-pill);
  font: 500 24px/1.2 var(--kiosk-font-ui);
  color: var(--kiosk-text-primary);
}
.kv-bye__recap > img {
  width: 56px;
  height: 72px;
  object-fit: contain;
}
.kv-bye__recap b {
  font: 800 26px/1 var(--kiosk-font-display);
  color: var(--kiosk-grow-2);
  margin-left: 6px;
}

/* ============================================================================
   spinJoy · Side F / B 提案（2026-11-09；docs/flow-spec.md §3）
   ----------------------------------------------------------------------------
   兩片 1080×1920 直式、不能觸控、不放要讀的小字（上一案的分工：Side F 配角、Side B 廣告位；只跟階段換、不逐步變）。
   Side F（前，Center 下方）：待機 品牌牆 → 互動中 本週優惠 → 帶位中 跟我走 + 走道 → 抵達 走道牌 + 商品。
   Side B（後，背面）：永遠本週優惠海報；帶位中上方多一條「前往 B3」。尺度用 DS 的 side token（title 88 / meta 34）。
   ============================================================================ */
.kv-sf, .kv-sb { padding: 96px 80px; display: flex; flex-direction: column; gap: 40px; }
.kv-sf__eyebrow, .kv-sb__eyebrow { font: 600 28px/1 var(--kiosk-font-mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--kiosk-text-secondary); }
.kv-sf__eyebrow--deal, .kv-sb__eyebrow--deal { color: var(--kiosk-accent-amber); }
.kv-sf__title, .kv-sb__title { font: var(--kiosk-type-side-title); letter-spacing: -0.01em; }
.kv-sf__title--xl { font-size: 136px; line-height: 1.05; }
.kv-sf__sub { font: var(--kiosk-type-side-meta); color: var(--kiosk-text-muted-light); }
.kv-sf__line { width: 360px; height: 4px; border-radius: 4px; background: var(--kiosk-grow); }
.kv-sf__spacer { flex: 1; }

/* 待機：我能做的三件事 */
.kv-sf__can { display: flex; flex-direction: column; gap: 20px; }
.kv-sf__can-item { display: flex; align-items: center; gap: 28px; padding: 28px 36px; border-radius: var(--kiosk-radius-card); background: var(--kiosk-glass-info); box-shadow: inset 0 0 0 1px var(--kiosk-line-info); font: 600 40px/1.2 var(--kiosk-font-ui); }
.kv-sf__can-icon { flex: none; width: 88px; height: 88px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: rgba(255, 255, 255, 0.10); }
.kv-sf__can-icon svg { width: 44px; height: 44px; }
.kv-sf__hint { font: 700 64px/1.1 var(--kiosk-font-ui); letter-spacing: 0.02em; }

/* 本週優惠：三列（Side F 互動中、Side B 永遠） */
.kv-sf__deals, .kv-sb__deals { display: flex; flex-direction: column; gap: 24px; }
.kv-sdeal { position: relative; display: flex; align-items: center; gap: 36px; height: 300px; padding: 24px; border-radius: var(--kiosk-radius-card); background: var(--kiosk-glass-info); box-shadow: inset 0 0 0 1px var(--kiosk-line-info); }
.kv-sdeal__img { flex: none; width: 240px; height: 100%; display: flex; align-items: center; justify-content: center; border-radius: 24px; background: rgba(255, 255, 255, 0.06); padding: 20px; }
.kv-sdeal__img > img { height: 100%; max-width: 100%; object-fit: contain; }
.kv-sdeal__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 14px; }
.kv-sdeal__name { font: 700 40px/1.2 var(--kiosk-font-ui); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.kv-sdeal__row { display: flex; align-items: baseline; gap: 20px; }
.kv-sdeal__price { font: 800 56px/1 var(--kiosk-font-display); }
.kv-sdeal__size { font: 500 30px/1 var(--kiosk-font-ui); color: var(--kiosk-text-secondary); }
.kv-sdeal__tag { display: inline-flex; align-items: center; height: 56px; padding: 0 20px; border-radius: 12px; background: var(--kiosk-accent-amber); color: var(--kiosk-surface-base); font: 700 28px/1 var(--kiosk-font-ui); white-space: nowrap; align-self: flex-start; }

/* 帶位中：大箭頭 + 走道 */
.kv-sf__arrows { display: flex; gap: 8px; font: 800 220px/1 var(--kiosk-font-display); background: var(--kiosk-grow); -webkit-background-clip: text; background-clip: text; color: transparent; margin: -24px 0 -40px -12px; }
.kv-sf__dest { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 12px; align-self: flex-start; padding: 32px 48px; border-radius: 48px; background: var(--kiosk-glass-pill); box-shadow: inset 0 0 0 2px var(--kiosk-line-tap); font: 500 34px/1 var(--kiosk-font-ui); color: var(--kiosk-text-muted-light); } /* 兩行：上面「Heading to」、下面目的地；Spinjoy · Front entrance 這種長的才放得下 */
.kv-sf__dest b { font: 800 46px/1.1 var(--kiosk-font-display); color: var(--kiosk-grow-2); } /* 46：「Spinjoy · Front entrance」在 Unbounded 要一行 */

/* 抵達：走道牌 + 商品 */
.kv-sf__code { font: 800 300px/1 var(--kiosk-font-display); letter-spacing: -0.02em; margin: -16px 0 -24px -8px; }
.kv-sf__pair { display: flex; gap: 24px; }
.kv-sf__pair > .kv-sdeal { flex: 1; height: 360px; flex-direction: column; align-items: stretch; gap: 20px; }
.kv-sf__pair .kv-sdeal__img { width: 100%; height: 180px; }

/* Side B：帶位中上方一條 */
.kv-sb__strip { display: none; align-items: center; gap: 24px; padding: 28px 36px; border-radius: var(--kiosk-radius-card); background: var(--kiosk-glass-pill); box-shadow: inset 0 0 0 2px var(--kiosk-line-tap); font: 600 36px/1.2 var(--kiosk-font-ui); }
.kv-sb__strip b { font: 800 44px/1 var(--kiosk-font-display); color: var(--kiosk-grow-2); }
.kv-sb.is-go > .kv-sb__strip { display: flex; }
/* Side B 底部：店內服務帶（Spinjoy 是這案的客戶，提案放一條；要不要放待設計師定） */
.kv-sb__band { margin-top: auto; display: flex; align-items: center; gap: 28px; padding: 32px 36px; border-radius: var(--kiosk-radius-card); background: var(--kiosk-glass-info); box-shadow: inset 0 0 0 1px var(--kiosk-line-info); }
.kv-sb__band > img { height: 56px; }
.kv-sb__band-text { font: 500 30px/1.3 var(--kiosk-font-ui); color: var(--kiosk-text-muted-light); }
.kv-sb__band-text b { display: block; font: 700 36px/1.2 var(--kiosk-font-ui); color: var(--kiosk-text-primary); }
