/* Kiosk page layout: header (brand, station, clock) / stage (face + subtitles, cards) / privacy
   footer. Full screen in portrait and landscape, sizes follow the viewport (vmin), no scrolling.
   With a camera (hello.camera) the live frame becomes the background and Mèo floats in a corner:
   see "camera stage" at the end. */

:root {
  --ink: var(--brand-ink, #111111);
  --ink-2: var(--brand-ink-2, #4A4A4A);
  --paper: var(--brand-paper, #FFF5F9);
  --gutter: clamp(12px, 2.4vmin, 32px);
  --header-h: clamp(46px, 6.6vmin, 74px);
  --font: var(--brand-font, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);
  --font-zh: var(--brand-font-zh, "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif);
  --card-shadow: 0 0.8vmin 3.2vmin rgba(17, 17, 17, 0.12);
  /* Powder-pink interface, deep plum text (16/10/2026). */
  --bar-glass: rgba(253, 226, 237, 0.86);
  --bar-edge: rgba(255, 255, 255, 0.8);
  --bar-ink: #8A4A69;
  --bar-strong: #5E2A45;
  --bar-line: rgba(138, 74, 105, 0.22);
  color-scheme: light;
}

* { box-sizing: border-box; }

html,
body {
  height: 100%;
  margin: 0;
  overflow: hidden;
  background: var(--paper);
}

body {
  font-family: var(--font);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  overscroll-behavior: none;
}

:lang(zh-Hans) { font-family: var(--font-zh); }
[hidden] { display: none !important; }

.hide-cursor,
.hide-cursor * { cursor: none !important; }

.app {
  position: fixed;
  inset: 0;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  background: radial-gradient(circle at 50% 46%, #FFF7FA 0%, #FCE4EE 48%, #F8CFE0 100%);
  transition: background-color 0.8s ease, color 0.8s ease;
}
.app[data-state="sleep"] {
  background: radial-gradient(circle at 50% 44%, #F6D3E1 0%, #EDB9CE 62%, #E3A6BF 100%);
  color: #5E2A45;
}
.app[data-state="offline"] {
  background: radial-gradient(circle at 50% 46%, #FBF3F6 0%, #F0E2E8 70%, #E6D5DD 100%);
}

/* ---------- status bar: one glass strip at the top edge ----------
   brand · Mèo · Lễ tân  |  ● live · station · voice of the day · office hours · clock (short values, icons say what) */
.top {
  position: relative;
  height: var(--header-h);
  padding: clamp(6px, 1vmin, 12px) var(--gutter) 0;
}
.status-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2vmin;
  height: 100%;
  padding: 0 clamp(12px, 2vmin, 24px);
  border: 1px solid var(--bar-edge);
  border-radius: 999px;
  background: var(--bar-glass);
  -webkit-backdrop-filter: blur(18px) saturate(1.5);
  backdrop-filter: blur(18px) saturate(1.5);
  box-shadow: 0 0.4vmin 2.4vmin rgba(17, 17, 17, 0.08);
  color: var(--bar-ink);
  font-size: clamp(12px, 1.75vmin, 19px);
  white-space: nowrap;
  transition: background-color 0.8s ease, color 0.8s ease;
}
.app[data-state="sleep"] {
  --bar-glass: rgba(246, 206, 223, 0.88);
}
.brand {
  display: flex;
  align-items: center;
  gap: 1.4vmin;
  min-width: 0;
}
.brand-logo {
  display: block;
  height: clamp(20px, 2.9vmin, 32px);
  width: auto;
}
.brand-logo.night { display: none; }
.brand-text {
  font-weight: 800;
  font-size: 1.3em;
  color: var(--brand-primary, #DA251D);
  letter-spacing: 0.02em;
}
.app-name {
  padding-left: 1.4vmin;
  border-left: 1px solid var(--bar-line);
  font-weight: 600;
}
.status {
  display: flex;
  align-items: center;
  gap: clamp(10px, 2.2vmin, 26px);
  min-width: 0;
  overflow: hidden;
}
.st {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  min-width: 0;
}
.st .icon { flex: none; width: 1.2em; height: 1.2em; opacity: 0.75; }
.st-station { color: var(--bar-strong); font-weight: 600; }
/* Asleep: the office hours are what a visitor needs, so they stand out. */
.app[data-state="sleep"] .st-hours { color: #C2185B; }
.app[data-state="sleep"] .st-hours .icon { opacity: 1; }
.clock { gap: 0.6em; align-items: baseline; }
.clock-time {
  color: var(--bar-strong);
  font-size: 1.3em;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.clock-date { opacity: 0.85; }
.connecting {
  padding: 0.15em 0.8em;
  border-radius: 999px;
  background: var(--bar-line);
  font-size: 0.92em;
}
.status .cam-live { display: none; color: var(--bar-strong); font-weight: 600; }

/* "Mèo chiến" button (js/guard.js, D48): a chip of the status bar; BAT red while guard mode is on, gold when armed. */
.guard-btn {
  flex: none;
  padding: 0.45em 0.9em;
  border: 1px solid var(--bar-line);
  border-radius: 999px;
  background: transparent;
  color: var(--bar-strong);
  font: inherit;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.guard-btn .icon { opacity: 1; }
.guard-btn:active { transform: scale(0.96); }
.guard-btn.is-on {
  border-color: #DA251D;
  background: #DA251D;
  color: #FFFFFF;
  animation: guard-pulse 2.4s ease-in-out infinite;
}
.guard-btn.is-armed { border-color: #FFCD00; background: #FFCD00; color: #111111; animation: none; }
@keyframes guard-pulse { 50% { box-shadow: 0 0 0 0.6vmin rgba(218, 37, 29, 0.3); } }
@media (prefers-reduced-motion: reduce) { .guard-btn.is-on { animation: none; } }

/* Guard view (js/guard.js GuardView): the guard camera live over the stage while guard mode is on and nobody talks
   to Mèo; the "Mèo ơiii" button (z-index 3) stays on top. */
.guard-view {
  position: absolute;
  inset: 0 var(--gutter) 1vmin;
  z-index: 2;
  overflow: hidden;
  border: 0.7vmin solid #DA251D;
  border-radius: 2vmin;
  background: #0B0B0B;
  color: #FFFFFF;
}
.guard-view.is-locked { animation: guard-lock 1.6s ease-in-out infinite; }
@keyframes guard-lock { 50% { border-color: #FFCD00; } }
.guard-cam {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.guard-wait {
  display: none;
  position: absolute;
  inset: 0;
  margin: auto;
  height: fit-content;
  text-align: center;
  font-size: clamp(16px, 2.6vmin, 30px);
  opacity: 0.8;
}
.guard-view.is-waiting .guard-wait { display: block; }
.guard-banner {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  gap: 1.2vmin;
  padding: 1.2vmin 2.4vmin;
  background: rgba(218, 37, 29, 0.92);
  font-size: clamp(16px, 2.8vmin, 32px);
  letter-spacing: 0.04em;
}
.guard-banner .icon { width: 1.3em; height: 1.3em; }
.guard-banner #guard-since { margin-left: auto; font-weight: 600; opacity: 0.9; }
.guard-foot {
  position: absolute;
  left: 2vmin;
  bottom: 2vmin;
  display: flex;
  align-items: center;
  gap: 1.6vmin;
  max-width: calc(100% - 36vmin);
  flex-wrap: wrap;
}
.guard-status {
  padding: 1vmin 2vmin;
  border-radius: 999px;
  background: rgba(17, 17, 17, 0.72);
  font-size: clamp(15px, 2.4vmin, 28px);
  font-weight: 600;
}
.guard-status[data-mode="follow"] { background: rgba(218, 37, 29, 0.9); }
.guard-off {
  display: inline-flex;
  align-items: center;
  gap: 1vmin;
  padding: 1.2vmin 2.6vmin;
  border: 2px solid #FFFFFF;
  border-radius: 999px;
  background: rgba(17, 17, 17, 0.55);
  color: #FFFFFF;
  font: 700 clamp(15px, 2.4vmin, 28px)/1 var(--font);
  cursor: pointer;
}
.guard-off .icon { width: 1.2em; height: 1.2em; }
.guard-off.is-armed { border-color: #FFCD00; background: #FFCD00; color: #111111; }
.guard-off:active { transform: scale(0.96); }
@media (prefers-reduced-motion: reduce) { .guard-view.is-locked { animation: none; } }

/* Narrow screens (portrait iPad, phones): drop the least useful parts first. */
@media (max-width: 960px) {
  .app-name,
  .clock-date { display: none; }
}
@media (max-width: 640px) {
  .st-voice,
  .app:not([data-state="sleep"]) .st-hours { display: none; }
}

/* ---------- stage ---------- */
.stage {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  min-height: 0;
}
.face-area {
  position: relative;
  min-width: 0;
  min-height: 0;
}
.avatar,
.face {
  position: absolute;
  inset: 0;
}
.face .meo-cat {
  width: 100%;
  height: 100%;
}
/* Mèo Tôm takes over from Mèo (js/main.js hostSwitcher): a short fade between the two faces. */
.face { transition: opacity 0.28s ease; }
.face.is-swapping { opacity: 0; }
.loading {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  margin: 0;
  color: var(--ink-2);
  font-size: clamp(16px, 3vmin, 32px);
}

/* Greeting chip when someone arrives (under the header; on the camera stage it hangs above the face). */
.greet {
  position: absolute;
  top: calc(env(safe-area-inset-top) + var(--header-h) + 2.4vmin);
  left: calc(env(safe-area-inset-left) + var(--gutter));
  display: flex;
  align-items: center;
  gap: 1.4vmin;
  max-width: min(46%, 640px);
  padding: 1.2vmin 2.8vmin 1.2vmin 1.6vmin;
  border: 2px solid var(--brand-primary, #DA251D);
  border-radius: 999px;
  background: var(--paper);
  box-shadow: var(--card-shadow);
}
.greet.is-new { animation: kiosk-pop-in 0.5s cubic-bezier(0.2, 0.8, 0.3, 1.25); }
.greet .icon {
  flex: none;
  width: clamp(30px, 5vmin, 56px);
  height: clamp(30px, 5vmin, 56px);
  stroke: var(--brand-primary, #DA251D);
}
.greet-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.2;
}
.greet-hello { color: var(--ink-2); font-size: clamp(14px, 2.1vmin, 24px); }
.greet.is-anon .greet-hello { color: var(--ink); font-weight: 700; font-size: clamp(16px, 2.8vmin, 32px); }
.greet-name {
  font-size: clamp(18px, 3.2vmin, 38px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.greet-title { color: var(--ink-2); font-size: clamp(13px, 1.9vmin, 21px); }

/* "Mất kết nối" badge. */
.badge {
  position: absolute;
  top: 2.4vmin;
  right: var(--gutter);
  display: flex;
  align-items: center;
  gap: 1.2vmin;
  max-width: min(44%, 560px);
  padding: 1vmin 2.4vmin 1vmin 1.6vmin;
  border: 2px solid #9C99A3;
  border-radius: 999px;
  background: var(--paper);
  color: #4A4A4A;
  box-shadow: var(--card-shadow);
  font-size: clamp(13px, 1.9vmin, 21px);
  animation: kiosk-pop-in 0.4s ease;
}
.badge .icon {
  flex: none;
  width: clamp(22px, 3.4vmin, 38px);
  height: clamp(22px, 3.4vmin, 38px);
  stroke: #8A8692;
}
.badge-text { display: flex; flex-direction: column; line-height: 1.25; }
.badge-text strong { color: #111111; font-size: 1.15em; }

/* Subtitles: user line small and grey, Mèo's line large. */
.subs {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.8vmin;
  padding: 4vmin var(--gutter) 2vmin;
  text-align: center;
  pointer-events: none;
  background: linear-gradient(to top, rgba(253, 232, 240, 0.97) 0%, rgba(253, 232, 240, 0.93) 60%, rgba(253, 232, 240, 0) 100%);
  transition: opacity 0.6s ease;
}
.app:not(.has-subs) .subs { background: none; }
.app[data-state="sleep"] .subs,
.app[data-state="offline"] .subs { opacity: 0; }
.sub-user {
  margin: 0;
  max-width: 60ch;
  color: #8A4A69;
  font-size: clamp(16px, 2.6vmin, 30px);
  line-height: 1.3;
  overflow-wrap: anywhere;
}
.sub-user.is-partial { font-style: italic; opacity: 0.75; }
.sub-meo {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
  margin: 0;
  max-width: 34ch;
  font-size: clamp(24px, 4.6vmin, 60px);
  font-weight: 650;
  line-height: 1.22;
  overflow-wrap: anywhere;
}
.sub-meo.is-long { font-size: clamp(21px, 3.8vmin, 48px); max-width: 40ch; }
.sub-meo.is-xlong { font-size: clamp(18px, 3.1vmin, 40px); max-width: 46ch; }
.sub-tag {
  display: inline-block;
  margin-right: 0.45em;
  padding: 0.12em 0.6em;
  border-radius: 999px;
  background: var(--brand-primary, #DA251D);
  color: #FFFFFF;
  font-size: 0.46em;
  font-weight: 700;
  letter-spacing: 0.05em;
  vertical-align: 0.28em;
}
.sub-user.is-new,
.sub-meo.is-new { animation: kiosk-rise 0.35s ease-out; }
.sub-tail { display: none; }

/* Night message while sleeping. */
.sleep-note {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 6vmin var(--gutter) 2.6vmin;
  background: linear-gradient(to top, rgba(240, 190, 212, 0.96) 0%, rgba(240, 190, 212, 0.86) 60%, rgba(240, 190, 212, 0) 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6vmin;
  margin: 0;
  color: #5E2A45;
  font-size: clamp(15px, 2.5vmin, 30px);
  text-align: center;
}

/* ---------- cards ---------- */
.cards {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.8vmin;
  width: 0;
  overflow: hidden;
  transition: width 0.45s ease, padding 0.45s ease;
}
.app.has-cards .cards {
  width: min(38vw, 560px);
  padding: 2vmin var(--gutter) 2vmin 0;
}
.card {
  position: relative;
  display: flex;
  gap: 1.8vmin;
  min-width: min(34vw, 520px);
  padding: 2vmin 2.2vmin 2.6vmin;
  border-left: 0.9vmin solid var(--brand-primary, #DA251D);
  border-radius: 2vmin;
  background: var(--paper);
  box-shadow: var(--card-shadow);
  overflow: hidden;
  animation: kiosk-card-in 0.45s cubic-bezier(0.2, 0.8, 0.3, 1.15);
}
.card--notice { border-left-color: var(--ink); }
.card.is-leaving { animation: kiosk-card-out 0.38s ease forwards; }
.card-photo {
  flex: none;
  width: clamp(64px, 12vmin, 140px);
  height: clamp(64px, 12vmin, 140px);
  border-radius: 1.4vmin;
  overflow: hidden;
  background: #F1EEF3;
}
.card-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.card-body { min-width: 0; }
.card-kind {
  display: flex;
  align-items: center;
  gap: 0.5em;
  color: var(--brand-primary, #DA251D);
  font-size: clamp(12px, 1.8vmin, 19px);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.card--notice .card-kind { color: var(--ink); }
.card-kind .icon { width: 1.35em; height: 1.35em; stroke: currentColor; }
.card-title {
  margin: 0.35em 0 0.25em;
  font-size: clamp(18px, 3vmin, 36px);
  line-height: 1.2;
  overflow-wrap: anywhere;
}
.card-lines {
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--ink-2);
  font-size: clamp(14px, 2.2vmin, 26px);
  line-height: 1.35;
  overflow-wrap: anywhere;
}
.card-ttl {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 0.6vmin;
  min-height: 3px;
}
.card-ttl span {
  display: block;
  height: 100%;
  background: var(--brand-primary, #DA251D);
  opacity: 0.35;
  transform-origin: left center;
  animation-name: kiosk-ttl;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}

/* ---------- footer: camera notice ---------- */
.privacy {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1vmin;
  padding: 0.9vmin var(--gutter) 1.1vmin;
  border-top: 3px solid #F2B5CD;
  color: #8A4A69;
  font-size: clamp(12px, 1.8vmin, 20px);
}
.app[data-state="sleep"] .privacy { color: #5E2A45; }
.privacy .icon { flex: none; width: 1.4em; height: 1.4em; stroke: currentColor; }
.privacy-text { transition: opacity 0.45s ease; }
.privacy-text.is-fading { opacity: 0; }

/* Inline icons from js/icons.js. */
.icon {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Wake-lock fallback video: must stay "visible" for the browser to count it. */
.keepawake {
  position: fixed;
  left: 0;
  bottom: 0;
  width: 2px;
  height: 2px;
  opacity: 0.01;
  pointer-events: none;
}

/* ---------- portrait: cards under the face ---------- */
@media (orientation: portrait) {
  .stage {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto;
  }
  .cards {
    width: auto;
    max-height: 0;
    padding: 0 var(--gutter);
    transition: max-height 0.45s ease, padding 0.45s ease;
  }
  .app.has-cards .cards {
    width: auto;
    max-height: 42vh;
    padding: 0 var(--gutter) 1.8vmin;
  }
  .card { min-width: 0; }
  .greet {
    left: 50%;
    max-width: 88%;
    transform: translateX(-50%);
  }
  .greet.is-new { animation-name: kiosk-pop-in-centred; }
  .badge { max-width: 70%; }
}

@keyframes kiosk-pop-in { from { opacity: 0; transform: scale(0.85); } to { opacity: 1; transform: scale(1); } }
@keyframes kiosk-pop-in-centred {
  from { opacity: 0; transform: translateX(-50%) scale(0.85); }
  to { opacity: 1; transform: translateX(-50%) scale(1); }
}
@keyframes kiosk-rise { from { opacity: 0; transform: translateY(1.2vmin); } to { opacity: 1; transform: none; } }
@keyframes kiosk-card-in { from { opacity: 0; transform: translateX(4vmin); } to { opacity: 1; transform: none; } }
@keyframes kiosk-card-out { to { opacity: 0; transform: translateX(4vmin); } }
@keyframes kiosk-ttl { from { transform: scaleX(1); } to { transform: scaleX(0); } }

@media (prefers-reduced-motion: reduce) {
  .cam-dot { animation: none; }
  .greet.is-new,
  .card,
  .sub-user.is-new,
  .sub-meo.is-new { animation: none; }
}

/* ---------- camera stage (hello.camera; ?camera=0 keeps Mèo full screen) ----------
   Layers: live frame (blurred while the lobby is empty, sharp when someone is there or Mèo is talking)
   + dark scrims for the header and footer text / lock ring on the visitor's face with the greeting
   above it / Mèo floating bottom-left in a glass arch, speech bubble beside her, cards top-right. */
.app.has-camera {
  /* Width of Mèo's glass frame; the full-body art is 2:3, so the frame is 1.5x as tall. */
  --avatar: min(43vh, 29vw);
  --lift: 1.4vmin;
  --lock-d: clamp(104px, 19vmin, 250px);
  --glass: rgba(253, 232, 240, 0.92);
  --glass-edge: rgba(255, 255, 255, 0.82);
  --float-shadow: 0 1.2vmin 4.4vmin rgba(8, 10, 22, 0.32);
  background: #F8CFE0;
}

.cam-area {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background: radial-gradient(circle at 28% 24%, #FBE3EC 0%, #F3C9DA 56%, #EAB3C9 100%);
}
.cam {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Scaled up a little while blurred so the soft edges stay off screen. */
  transform: scale(1.08);
  filter: blur(16px) saturate(1.2) brightness(0.9);
  transition: filter 0.9s ease, transform 0.9s ease, opacity 0.6s ease;
}
.app.is-mirrored .cam { transform: scale(-1.08, 1.08); }
.app.is-engaged .cam { transform: none; filter: none; }
.app.is-engaged.is-mirrored .cam { transform: scaleX(-1); }
.app[data-state="sleep"] .cam { filter: blur(24px) saturate(0.6) brightness(0.55); }
/* Woken by a face after hours: the room comes into focus, still dimmed for the night. */
.app.is-roused[data-state="sleep"] .cam { transform: none; filter: saturate(0.85) brightness(0.8); }
.app.is-roused.is-mirrored[data-state="sleep"] .cam { transform: scaleX(-1); }
.app[data-state="offline"] .cam { filter: blur(16px) grayscale(1) brightness(0.7); }
.cam-area.cam-waiting .cam { opacity: 0; }
.cam-area::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(252, 220, 233, 0.4) 0%, rgba(252, 220, 233, 0) 16%,
    rgba(252, 220, 233, 0) 62%, rgba(252, 220, 233, 0.78) 100%);
  transition: background-color 0.8s ease;
}
.app[data-state="sleep"] .cam-area::after { background-color: rgba(236, 172, 199, 0.55); }
.app.is-roused[data-state="sleep"] .cam-area::after { background-color: rgba(236, 172, 199, 0.25); }
.cam-wait {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: none;
  place-items: center;
  color: #8A4A69;
  font-size: clamp(14px, 2.2vmin, 24px);
}
.cam-area.cam-waiting .cam-wait { display: grid; }

/* Stand-in visitor for ?demo=1 (no real camera); the head sits where the lock ring is. */
.cam-stand-in {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  width: calc(var(--lock-d) * 1.9);
  height: auto;
  transform: translate(var(--lock-x), var(--lock-y)) translate(-50%, -14%);
  transition: transform 0.22s linear;
}

/* Lock ring on the visitor's face: pops in, then breathes. */
.ar-lock {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  width: var(--lock-d);
  height: var(--lock-d);
  border: max(2px, 0.32vmin) solid rgba(255, 255, 255, 0.92);
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.12), 0 0 2.6vmin rgba(255, 255, 255, 0.35), inset 0 0 2vmin rgba(255, 255, 255, 0.18);
  pointer-events: none;
  transform: translate(var(--lock-x), var(--lock-y)) translate(-50%, -50%);
  transition: transform 0.22s linear;
  animation: lock-in 0.5s cubic-bezier(0.2, 0.8, 0.3, 1.2);
}
.ar-lock::after {
  content: "";
  position: absolute;
  inset: -1.2vmin;
  border: max(2px, 0.28vmin) solid var(--brand-primary, #DA251D);
  border-radius: 50%;
  animation: lock-pulse 2.4s ease-out infinite;
}

/* On the camera: the same pink glass bar; the footer is plum text over the pink haze at the bottom. */
.app.has-camera .status-bar { box-shadow: 0 0.6vmin 3vmin rgba(138, 74, 105, 0.18); }
.app.has-camera .privacy { border-top-color: transparent; color: #5E2A45; }
.app.has-camera .status .cam-live { display: inline-flex; }
.cam-area.cam-waiting ~ .top .status .cam-live,
.app[data-state="offline"] .status .cam-live { display: none; }
.cam-dot {
  width: 1.1vmin;
  height: 1.1vmin;
  min-width: 7px;
  min-height: 7px;
  border-radius: 50%;
  background: var(--brand-primary, #DA251D);
  box-shadow: 0 0 0.8vmin var(--brand-primary, #DA251D);
  animation: kiosk-live 1.6s ease-in-out infinite;
}
@keyframes kiosk-live { 50% { opacity: 0.35; } }

/* Stage: Mèo, subtitles and cards float over the frame instead of sharing a grid. */
.app.has-camera .stage { display: block; }
.app.has-camera .face-area {
  position: absolute;
  inset: 0;
}

/* Mèo in a glass arch, floating; the ears break out of the top of the arch. */
.app.has-camera .avatar {
  top: auto;
  right: auto;
  bottom: calc(1.2vmin + var(--lift));
  left: var(--gutter);
  width: var(--avatar);
  height: calc(var(--avatar) * 1.5);
  isolation: isolate;
  animation: holo-float 6s ease-in-out infinite;
}
.app.has-camera .face { z-index: 1; }
.app.has-camera .face::before {
  content: "";
  position: absolute;
  top: 13%;
  right: 6%;
  bottom: 0;
  left: 6%;
  border: 1.5px solid var(--glass-edge);
  border-radius: calc(var(--avatar) * 0.44) calc(var(--avatar) * 0.44) 3.2vmin 3.2vmin;
  background: linear-gradient(to bottom, rgba(255, 236, 244, 0.55) 0%, rgba(253, 226, 237, 0.88) 70%, rgba(252, 220, 233, 0.95) 100%);
  -webkit-backdrop-filter: blur(16px) saturate(1.3);
  backdrop-filter: blur(16px) saturate(1.3);
  box-shadow: var(--float-shadow);
}
.app.has-camera .face .meo-cat { position: relative; }
.app.has-camera .face .loading { color: var(--ink-2); }
/* State ring around the arch: listening pulses, thinking glows slowly, speaking flickers with the voice. */
.app.has-camera .avatar::after {
  content: "";
  position: absolute;
  top: calc(13% - 0.9vmin);
  right: calc(6% - 0.9vmin);
  bottom: -0.9vmin;
  left: calc(6% - 0.9vmin);
  z-index: 0;
  border: max(2px, 0.36vmin) solid var(--brand-primary, #DA251D);
  border-radius: calc(var(--avatar) * 0.44 + 0.9vmin) calc(var(--avatar) * 0.44 + 0.9vmin) 4vmin 4vmin;
  box-shadow: 0 0 2.4vmin var(--brand-primary, #DA251D);
  opacity: 0.32;
  transition: opacity 0.5s ease;
}
.app.has-camera[data-state="listening"] .avatar::after { animation: holo-listen 1.3s ease-in-out infinite; }
.app.has-camera[data-state="thinking"] .avatar::after { animation: holo-think 2.4s ease-in-out infinite; }
.app.has-camera[data-state="speaking"] .avatar::after { animation: holo-speak 0.7s ease-in-out infinite alternate; }
.app.has-camera[data-state="sleep"] .avatar::after,
.app.has-camera[data-state="offline"] .avatar::after { opacity: 0; }
.app.has-camera.is-roused[data-state="sleep"] .avatar::after { opacity: 0.5; }
.app.has-camera[data-state="sleep"] .face::before {
  border-color: rgba(255, 255, 255, 0.6);
  background: linear-gradient(to bottom, rgba(242, 190, 212, 0.6) 0%, rgba(232, 168, 196, 0.9) 100%);
}
.app.has-camera[data-state="offline"] .face::before { background: linear-gradient(to bottom, rgba(238, 237, 241, 0.6), rgba(228, 227, 232, 0.92)); }
/* Soft shadow on the floor: smaller while Mèo is up. */
.app.has-camera .face-area::after {
  content: "";
  position: absolute;
  bottom: 0.2vmin;
  left: calc(var(--gutter) + var(--avatar) * 0.14);
  width: calc(var(--avatar) * 0.72);
  height: 2.4vmin;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0));
  animation: holo-shadow 6s ease-in-out infinite;
}

/* Speech: Mèo's line is a bubble pointing at her, the visitor's line a dark chip on the right. */
.app.has-camera .subs {
  right: var(--gutter);
  bottom: calc(1.2vmin + var(--lift) + var(--avatar) * 0.14);
  left: calc(var(--gutter) + var(--avatar) + 2.2vmin);
  align-items: flex-start;
  gap: 1.2vmin;
  padding: 0;
  text-align: left;
  background: none;
}
.app.has-camera .sub-user {
  align-self: flex-end;
  max-width: 82%;
  padding: 1vmin 2.2vmin;
  border-radius: 2.6vmin 2.6vmin 0.6vmin 2.6vmin;
  background: rgba(110, 48, 80, 0.72);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  color: rgba(255, 255, 255, 0.94);
  font-size: clamp(15px, 2.3vmin, 28px);
}
.app.has-camera .sub-meo {
  max-width: 100%;
  padding: 1.6vmin 2.8vmin 1.9vmin;
  border: 1px solid var(--glass-edge);
  border-radius: 3.2vmin;
  background: var(--glass);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
  box-shadow: var(--float-shadow);
  color: var(--ink);
}
.app.has-camera .sub-tail {
  display: block;
  position: absolute;
  bottom: 2.6vmin;
  left: -2.2vmin;
  width: 2.4vmin;
  height: 3.2vmin;
  background: var(--glass);
  -webkit-clip-path: polygon(100% 0, 0 55%, 100% 100%);
  clip-path: polygon(100% 0, 0 55%, 100% 100%);
}
.sub-meo[hidden] + .sub-tail { display: none; }
.app.has-camera .sleep-note {
  right: var(--gutter);
  bottom: calc(1.2vmin + var(--lift) + var(--avatar) * 0.14);
  left: calc(var(--gutter) + var(--avatar) + 2.2vmin);
  align-items: flex-start;
  padding: 2vmin 2.8vmin;
  border: 1px solid rgba(255, 255, 255, 0.7);
  border-radius: 3.2vmin;
  background: rgba(248, 210, 226, 0.9);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  text-align: left;
}

/* Cards: glass, top-right. */
.app.has-camera .cards,
.app.has-camera.has-cards .cards {
  position: absolute;
  top: 2vmin;
  right: var(--gutter);
  width: min(36vw, 520px);
  padding: 0;
  justify-content: flex-start;
  overflow: visible;
  transition: none;
}
.app.has-camera .card {
  min-width: 0;
  background: var(--glass);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
  box-shadow: var(--float-shadow);
}
.app.has-camera .badge { right: auto; left: 50%; translate: -50% 0; }

/* Greeting hangs above the lock ring (below it when the face is near the top), kept on screen. */
.app.has-camera .greet {
  background: var(--glass);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
  box-shadow: var(--float-shadow);
}
.app.has-lock .greet {
  top: calc(var(--lock-y) - var(--lock-d) / 2 - 2.6vmin);
  left: clamp(calc(var(--gutter) + min(25vw, 240px)), var(--lock-x), calc(100% - var(--gutter) - min(25vw, 240px)));
  max-width: min(50vw, 480px);
  transform: none;
  translate: -50% -100%;
  transition: top 0.22s linear, left 0.22s linear;
}
.app.has-lock.lock-high .greet {
  top: calc(var(--lock-y) + var(--lock-d) / 2 + 2.6vmin);
  translate: -50% 0;
}
.app.has-lock .greet.is-new { animation-name: kiosk-pop-in; }

@media (orientation: portrait) {
  .app.has-camera { --avatar: min(22vh, 34vw); }
  /* Bubble above Mèo across the width, cards beside her. */
  .app.has-camera .subs,
  .app.has-camera .sleep-note {
    left: var(--gutter);
    bottom: calc(1.2vmin + var(--lift) + var(--avatar) * 1.5 + 2.4vmin);
  }
  .app.has-camera .sub-tail {
    bottom: -2.2vmin;
    left: calc(var(--avatar) * 0.5 - 1.6vmin);
    width: 3.2vmin;
    height: 2.4vmin;
    -webkit-clip-path: polygon(0 0, 100% 0, 45% 100%);
    clip-path: polygon(0 0, 100% 0, 45% 100%);
  }
  .app.has-camera .cards,
  .app.has-camera.has-cards .cards {
    top: auto;
    bottom: calc(1.2vmin + var(--lift));
    left: calc(var(--gutter) + var(--avatar) + 2vmin);
    width: auto;
    max-height: none;
    justify-content: flex-end;
  }
  .app.has-lock .greet { transform: none; }
}

@keyframes holo-float { 50% { transform: translateY(calc(var(--lift) * -1)); } }
@keyframes holo-shadow { 50% { transform: scale(0.82); opacity: 0.7; } }
@keyframes holo-listen { 50% { opacity: 1; } }
@keyframes holo-think { 0%, 100% { opacity: 0.4; } 50% { opacity: 0.85; } }
@keyframes holo-speak { from { opacity: 0.55; } to { opacity: 1; } }
@keyframes lock-in { from { opacity: 0; scale: 1.7; } to { opacity: 1; scale: 1; } }
@keyframes lock-pulse { from { opacity: 0.9; transform: scale(0.92); } to { opacity: 0; transform: scale(1.3); } }

@media (prefers-reduced-motion: reduce) {
  .cam,
  .ar-lock,
  .cam-stand-in,
  .app.has-lock .greet { transition: none; }
  .ar-lock,
  .ar-lock::after,
  .app.has-camera .avatar,
  .app.has-camera .avatar::after,
  .app.has-camera .face-area::after { animation: none; }
}

/* Songs on the screen (D41, js/tube.js): YouTube's player in a card above everything. */
.tube {
  position: fixed;
  left: 50%;
  top: 50%;
  z-index: 50;
  width: min(92vw, 760px);
  transform: translate(-50%, -50%);
  padding: 14px 14px 10px;
  border-radius: 22px;
  background: rgba(17, 17, 17, 0.92);
  color: #fff;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.45);
}
.tube[hidden] { display: none; }
.tube-head { display: flex; align-items: center; gap: 10px; margin: 0 4px 10px; }
.tube-note { color: var(--brand-accent, #FFCD00); font-size: 1.6rem; line-height: 1; }
.tube-title { flex: 1; min-width: 0; font-weight: 700; font-size: 1.2rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tube-close,
.tube-play {
  border: 0;
  border-radius: 999px;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.tube-close { width: 40px; height: 40px; background: rgba(255, 255, 255, 0.14); color: #fff; }
.tube-frame { position: relative; aspect-ratio: 16 / 9; border-radius: 14px; overflow: hidden; background: #000; }
.tube-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.tube-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 44px; margin: 8px 4px 4px; }
.tube-hint { opacity: 0.85; }
.tube-play { padding: 10px 22px; background: var(--brand-primary, #DA251D); color: #fff; font-size: 1.1rem; }
.tube-track { height: 4px; margin: 4px; border-radius: 4px; background: rgba(255, 255, 255, 0.18); overflow: hidden; }
.tube-bar { display: block; height: 100%; width: 0; background: var(--brand-accent, #FFCD00); transition: width 0.25s linear; }

/* Awake: the pink steps back (16/10/2026). Pink is the mood of the empty lobby and the night; with someone at the
   counter or a conversation (.is-engaged, ui.js; also when a face wakes Mèo at night) the camera is clear and the
   panels are white glass with dark text, so the room and the visitor look natural. */
.app.is-engaged {
  --bar-glass: rgba(255, 255, 255, 0.86);
  --bar-ink: #5A4A52;
  --bar-strong: #2E2329;
  --bar-line: rgba(90, 74, 82, 0.2);
  --glass: rgba(255, 255, 255, 0.93);
  --paper: #FFFFFF;
  background: radial-gradient(circle at 50% 46%, #FFFFFF 0%, #FDF6F9 55%, #F5E8EE 100%);
}
.app.has-camera.is-engaged { background: #F5E8EE; }
.app.is-engaged .cam-area::after,
.app.is-roused.is-engaged[data-state="sleep"] .cam-area::after {
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 80%, rgba(255, 255, 255, 0.6) 100%);
}
.app.is-engaged .privacy { color: #4A3A42; }
.app.is-engaged .subs { background: linear-gradient(to top, rgba(255, 255, 255, 0.97) 0%, rgba(255, 255, 255, 0.93) 60%, rgba(255, 255, 255, 0) 100%); }
.app.has-camera.is-engaged .subs { background: none; }
.app.has-camera.is-engaged .sub-user { background: rgba(34, 28, 32, 0.62); }
.subs { transition: opacity 0.6s ease, background-color 0.8s ease; }
.card,
.greet,
.sub-meo,
.app.has-camera .sub-user { transition: background-color 0.8s ease, color 0.8s ease; }

/* "Mèo ơiii" button (js/wake.js): bottom-right; subtitles and the night note leave it room. */
.wake-btn {
  position: absolute;
  right: var(--gutter);
  bottom: 2.4vmin;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 1vmin;
  padding: 1.6vmin 3.2vmin;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #FF8FB3, #E0508F);
  color: #FFFFFF;
  font: 700 clamp(18px, 3.2vmin, 36px)/1 var(--font);
  box-shadow: 0 1vmin 3vmin rgba(224, 80, 143, 0.4);
  cursor: pointer;
  animation: wake-pulse 2.4s ease-in-out infinite;
}
.wake-btn .icon { width: 1.2em; height: 1.2em; }
.wake-btn:active { transform: scale(0.96); }
.wake-btn.is-waking { animation: none; opacity: 0.85; }
.app.has-wake .subs,
.app.has-wake .sleep-note { right: calc(var(--gutter) + 32vmin); }
@keyframes wake-pulse { 50% { box-shadow: 0 1vmin 3vmin rgba(224, 80, 143, 0.4), 0 0 0 1.4vmin rgba(255, 143, 179, 0.25); } }
@media (orientation: portrait) {
  .wake-btn { top: 2vmin; bottom: auto; }
  .app.has-wake .subs,
  .app.has-wake .sleep-note { right: var(--gutter); }
}
@media (prefers-reduced-motion: reduce) { .wake-btn { animation: none; } }
