/* Real-media host (js/photo.js): Mèo as looping video clips and photos. A framed 2:3 portrait centred in the
   face area; on the camera stage it fills Mèo's glass arch. The state shows as light effects over the picture. */
.photo-face {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 1.6vmin 0;
}
.photo-frame {
  position: relative;
  height: 100%;
  max-width: 100%;
  aspect-ratio: 2 / 3;
  border-radius: 3vmin;
  overflow: hidden;
  background: #E9E4EC;
  box-shadow: 0 1.2vmin 4vmin rgba(17, 17, 17, 0.18);
  transition: filter 0.8s ease;
}
/* Parallax towards the visitor (--gx/--gy set by setPresence). */
.photo-pan {
  position: absolute;
  inset: -3%;
  transform: translate(calc(var(--gx, 0) * -1.5%), calc(var(--gy, 0) * -1%));
  transition: transform 0.8s ease;
}
.photo-pan > img,
.photo-pan > video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.56s ease;
  animation: photo-breathe 8s ease-in-out infinite;
}
/* Clips move by themselves: no breathing zoom on <video> (a transformed video renders black on some GPUs). */
.photo-pan > video { animation: none; }
.photo-pan > .is-on { opacity: 1; }
.photo-pan > .is-top { z-index: 1; }
.photo-face.is-waving .photo-frame { animation: photo-hop 0.6s cubic-bezier(0.2, 0.8, 0.3, 1) 1; }

/* Night and offline looks. */
/* Asleep: Mèo's sleeping photo, only slightly dimmed (a dark frame looked like the screen was off). */
.photo-face[data-state="sleep"] .photo-frame { filter: brightness(0.9) saturate(0.9); }
.photo-face[data-state="offline"] .photo-frame { filter: grayscale(1) brightness(0.92); }

/* Listening: a soft brand-coloured glow breathing around the frame. */
.photo-frame::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 0.5vmin var(--brand-primary, #DA251D), inset 0 0 4vmin rgba(218, 37, 29, 0.35);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease;
}
.photo-face[data-state="listening"] .photo-frame::after { animation: photo-listen 1.3s ease-in-out infinite; }

/* Thinking: three dots in a bubble; speaking: voice bars; sleep: Z z z. */
.photo-dots,
.photo-talk,
.photo-zzz {
  position: absolute;
  display: none;
  pointer-events: none;
}
.photo-dots {
  top: 5%;
  right: 6%;
  gap: 0.9vmin;
  padding: 1.1vmin 1.6vmin;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.88);
  box-shadow: 0 0.6vmin 2vmin rgba(17, 17, 17, 0.18);
}
.photo-dots i {
  width: 1.3vmin;
  height: 1.3vmin;
  border-radius: 50%;
  background: #5B5066;
  animation: photo-dot 1.1s ease-in-out infinite;
}
.photo-dots i:nth-child(2) { animation-delay: 0.18s; }
.photo-dots i:nth-child(3) { animation-delay: 0.36s; }
.photo-face[data-state="thinking"] .photo-dots { display: flex; }
.photo-talk {
  left: 50%;
  bottom: 4%;
  align-items: center;
  gap: 0.7vmin;
  height: 5vmin;
  padding: 0 1.6vmin;
  border-radius: 999px;
  background: rgba(17, 15, 24, 0.45);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  transform: translateX(-50%);
}
.photo-talk i {
  width: 0.7vmin;
  min-width: 3px;
  height: 60%;
  border-radius: 999px;
  background: #FFFFFF;
  transform-origin: 50% 50%;
  animation: photo-bar 0.9s ease-in-out infinite;
}
.photo-talk i:nth-child(2) { animation-delay: -0.3s; }
.photo-talk i:nth-child(3) { animation-delay: -0.6s; }
.photo-talk i:nth-child(4) { animation-delay: -0.15s; }
.photo-talk i:nth-child(5) { animation-delay: -0.45s; }
.photo-face[data-state="speaking"] .photo-talk { display: flex; }
.photo-zzz {
  top: 5%;
  right: 8%;
  color: #DCE0F5;
  font-size: clamp(18px, 4vmin, 44px);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-shadow: 0 0.3vmin 1.2vmin rgba(0, 0, 0, 0.45);
  animation: photo-z 3.3s ease-in-out infinite;
}
.photo-face[data-state="sleep"] .photo-zzz { display: block; }

/* Camera stage: the photo fills Mèo's glass arch (same box as .face::before in kiosk.css). */
.app.has-camera .photo-face { padding: 0; }
.app.has-camera .photo-frame {
  position: absolute;
  top: 13%;
  right: 6%;
  bottom: 0;
  left: 6%;
  height: auto;
  aspect-ratio: auto;
  border-radius: calc(var(--avatar) * 0.44) calc(var(--avatar) * 0.44) 3.2vmin 3.2vmin;
  box-shadow: none;
}

/* ---------- full-bleed photo host (.app.face-photo, set by js/photo.js) ----------
   No frame: no glass arch, ring, rounded corners or drop shadow. The picture sits in the corner and fades into
   the background through a soft mask, so Mèo looks like she is in the room rather than in a box. */
.app.face-photo .photo-frame {
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  /* Every edge fades into the page: left/right here, top/bottom on .photo-face below. Two nested single-layer
     masks multiply, which works everywhere (mask-composite does not, in older Chromium and Safari 15). */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 14%, #000 86%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 14%, #000 86%, transparent);
}
.app.face-photo .photo-face {
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 10%, #000 88%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 10%, #000 88%, transparent);
}
/* Listening without a frame: a soft red glow rising from the bottom instead of a glowing border. */
.app.face-photo .photo-frame::after {
  border-radius: 0;
  box-shadow: none;
  background: radial-gradient(ellipse 70% 24% at 50% 100%, rgba(218, 37, 29, 0.55), rgba(218, 37, 29, 0));
}
/* Camera stage: a large portrait flush with the bottom-left corner, fading out towards the top and the right. */
.app.has-camera.face-photo { --avatar: min(56vh, 40vw); }
.app.has-camera.face-photo .avatar {
  bottom: 0;
  left: 0;
  animation: none;
}
.app.has-camera.face-photo .avatar::after,
.app.has-camera.face-photo .face::before,
.app.has-camera.face-photo .face-area::after { display: none; }
.app.has-camera.face-photo .photo-frame {
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  border-radius: 0;
  /* Flush with the screen's left and bottom edges; fades out over the right 38 % (here) and the top 16 % (below). */
  -webkit-mask-image: linear-gradient(to right, #000 62%, transparent);
  mask-image: linear-gradient(to right, #000 62%, transparent);
}
.app.has-camera.face-photo .photo-face {
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 16%);
  mask-image: linear-gradient(to bottom, transparent, #000 16%);
}
/* Keep the state marks inside the solid part of the picture. */
.app.face-photo .photo-dots,
.app.face-photo .photo-zzz { top: 16%; right: 24%; }
.app.face-photo .photo-talk { bottom: 6%; }
@media (orientation: portrait) {
  .app.has-camera.face-photo { --avatar: min(30vh, 54vw); }
}

@keyframes photo-breathe { 50% { transform: scale(1.03); } }
@keyframes photo-hop { 35% { transform: translateY(-2.4vmin); } 70% { transform: translateY(0.4vmin); } }
@keyframes photo-listen { 0%, 100% { opacity: 0.35; } 50% { opacity: 1; } }
@keyframes photo-dot { 0%, 60%, 100% { transform: translateY(0); } 30% { transform: translateY(-0.9vmin); } }
@keyframes photo-bar { 0%, 100% { transform: scaleY(0.35); } 50% { transform: scaleY(1); } }
@keyframes photo-z {
  0% { opacity: 0; transform: translate(0, 1vmin); }
  30%, 70% { opacity: 1; }
  100% { opacity: 0; transform: translate(1.2vmin, -2.4vmin); }
}

@media (prefers-reduced-motion: reduce) {
  .photo-pan,
  .photo-pan > img,
  .photo-pan > video { transition: none; animation: none; }
  .photo-face.is-waving .photo-frame,
  .photo-talk i,
  .photo-dots i,
  .photo-zzz { animation: none; }
}
