:root {
  --night: #17112a; /* the page: a violet night, not black */
  --dusk: #221a3a; /* the camera tile while it's off */
  --sheet: #f2edfb; /* text: the ghost's lavender-white sheet */
  --fog: #a69cc2; /* quieter text */
  --pumpkin: #ff6a13; /* the one action color */
  --candle: #ff8a2b; /* the title's light, and focus rings */
  --hole: #000000; /* the jump scare: a hole in the night */
  --ink: #0c0819; /* silhouettes and the ground */
  --line: rgb(242 237 251 / 0.14);
  --display: "Grenze Gotisch", Georgia, serif;
  --text: "Alegreya Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --gutter: 20px;
  color-scheme: dark;
}

* { box-sizing: border-box; }

/* Clipped here too: otherwise body's clip moves up to the window and stops clipping the glow. */
html { overflow-x: clip; -webkit-text-size-adjust: 100%; }

/* A column, so the ground and the footer stay at the bottom of a tall window. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
  margin: 0;
  overflow-x: clip;
  background: var(--night);
  color: var(--sheet);
  font-family: var(--text);
  font-size: 19px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; }

::selection { background: var(--pumpkin); color: var(--night); }

:focus-visible { outline: 3px solid var(--candle); outline-offset: 3px; }

/* Decorations: the page is a room done up for Halloween night. They stay in the
   margins and behind everything, and never cover the picture or the text. */
/* Positioned against the viewport, so body's clip doesn't reach it: it clips itself. */
.decor { position: absolute; top: 0; left: 0; right: 0; height: 360px; overflow: hidden; z-index: -1; pointer-events: none; }

/* The string lights twinkle, and come on with the title. */
.lights {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 64px;
  background: url("decor/lights-twinkle.svg") 0 0 / 280px 64px repeat-x;
  animation: catch 1.5s steps(1, end) both;
}

/* The corners stay small: the picture starts right under the title. */
.cobweb { position: absolute; top: 0; left: 0; width: clamp(104px, 12vw, 180px); }

/* Now and then a bat crosses the sky behind the title, one each way. */
.flight { position: absolute; top: 74px; left: 0; animation: fly 19s linear infinite; }
.flight-back { top: 116px; animation-name: fly-back; animation-duration: 23s; animation-delay: -9s; }
.flight .bob { animation: bob 1.5s ease-in-out infinite alternate; }
.flight img { display: block; width: 34px; animation: flap 0.24s ease-in-out infinite alternate; }
.flight-back img { width: 22px; animation-duration: 0.2s; }

/* It hangs from the web on a thread that starts above the top of the page, and stops above
   the picture. It sits over the page, not behind it, so it can feel the mouse coming. */
.spider {
  position: absolute;
  z-index: 1;
  top: -40px;
  left: calc(clamp(104px, 12vw, 180px) * 0.52);
  display: grid;
  justify-items: center;
  animation: dangle 5s ease-in-out infinite alternate;
}

.spider::before {
  content: "";
  width: 1px;
  height: clamp(80px, 7vw, 110px);
  background: linear-gradient(rgb(233 226 250 / 0.1), rgb(233 226 250 / 0.42));
}

.spider img { width: clamp(28px, 2.6vw, 38px); margin-top: -2px; }

.moon { position: absolute; top: 8px; right: 2vw; width: clamp(110px, 11vw, 170px); }

.page {
  flex: 1 0 auto;
  width: 100%;
  max-width: 1320px;
  margin: 0 auto;
  padding: max(60px, env(safe-area-inset-top)) var(--gutter) 40px;
}

.intro { text-align: center; margin-bottom: 22px; }

/* The title glows like a lamp in a dark house, and catches on like one. */
h1 {
  margin: 0;
  color: var(--candle);
  font-family: var(--display);
  font-size: clamp(44px, 9vw, 72px);
  font-weight: 850;
  line-height: 0.92;
  text-shadow: 0 0 0.18em rgb(255 106 19 / 0.55), 0 0 0.7em rgb(255 106 19 / 0.32);
  text-wrap: balance;
  animation: catch 1.5s steps(1, end) 0.15s both;
}

/* Meet's own logo, as Google draws it, so the name reads at a glance. */
.meet { white-space: nowrap; }
.meet img { height: 0.74em; width: auto; margin-right: 0.14em; vertical-align: -0.03em; }

/* The picture with its controls, and the looks next to it, like Meet's effects
   panel beside your preview. On a laptop all of it fits without scrolling. */
.hero { --ratio: 16 / 9; /* the camera's, once it's on */ }
.theater { min-width: 0; }

/* The screen: the live, haunted camera, the only light in the room once it's on. */
.screen { position: relative; }

/* It spills out to the sides and down, like a screen on a desk, and less up into the text. */
.glow {
  --spill: max(-12%, (100% - 100vw) / 2); /* as far as the window's edge, no further */
  position: absolute;
  top: -4%;
  left: var(--spill);
  width: calc(100% - 2 * var(--spill));
  height: 122%;
  z-index: -1; /* behind everything on the page, not over the looks under it */
  pointer-events: none;
  opacity: 0;
  filter: blur(48px) saturate(1.4);
  transform: scaleX(-1); /* mirrored, like the picture */
  transition: opacity 1.6s ease;
}

.screen[data-state="live"] .glow { opacity: 0.5; }

/* Centered: an upright phone camera makes it tall, and its height cap then narrows it. */
.stage {
  position: relative;
  margin: 0 auto;
  aspect-ratio: var(--ratio);
  border-radius: 24px;
  background: var(--dusk);
  overflow: hidden;
}

.stage canvas {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scaleX(-1); /* a mirror, like every selfie view */
  opacity: 0;
}

.screen[data-state="live"] .stage canvas { opacity: 1; }

/* Camera off: the tile shows the ghost you're about to be, like Meet shows your avatar. */
.stage-start {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 14px;
  padding: 20px;
  text-align: center;
}

.screen[data-state="live"] .stage-start { display: none; }

/* The ghost floats over its shadow and blinks; its eyes follow the mouse (app.ts sets
   --lx and --ly), and it leans in when the mouse reaches Turn on camera. */
.stage-ghost {
  width: clamp(58px, 10vw, 86px);
  height: auto;
  color: var(--sheet);
  filter: drop-shadow(0 0 22px rgb(242 237 251 / 0.22));
  transition: transform 220ms ease;
}

.ghost-body { animation: hover 1.8s ease-in-out infinite alternate; }
.ghost-shadow { fill: #000; opacity: 0.4; transform-box: fill-box; transform-origin: center; animation: shadow 1.8s ease-in-out infinite alternate; }
.ghost-eye,
.ghost-mouth { fill: var(--dusk); }
.ghost-eyes { transform: translate(var(--lx, 0px), var(--ly, 0px)); transition: transform 140ms ease-out; }
.ghost-mouth { transform: translate(calc(var(--lx, 0px) * 0.6), calc(var(--ly, 0px) * 0.6)); transition: transform 140ms ease-out; }
.ghost-eye { transform-box: fill-box; transform-origin: center; animation: blink 5.2s infinite; }

.stage-start:has(#start:hover) .stage-ghost { transform: translateY(-4px) scale(1.07); }

.stage-note { margin: 0; color: var(--fog); font-size: 15px; }

/* The controls sit under the looks: pick one, then haunt. They wake up once the camera is on. */
.actions { display: flex; justify-content: center; gap: 10px; margin-top: 16px; }

/* Under the picture: the status line, and a quiet way to turn the camera off, for the few
   who want to. It stays small and away from Haunt me; Turn on camera is the way back. */
.under { display: flex; align-items: center; gap: 12px; min-height: 34px; margin-top: 8px; }
.status { margin: 0; color: var(--fog); font-size: 15px; }

.camera-off {
  appearance: none;
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 7px;
  margin-left: auto;
  padding: 6px 12px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--fog);
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  transition: color 140ms ease, background-color 140ms ease;
}

.camera-off[hidden] { display: none; }
.camera-off svg { width: 18px; height: 18px; }

@media (hover: hover) {
  .camera-off:hover { color: var(--sheet); background: rgb(242 237 251 / 0.08); }
}

/* Each look is a picture of itself, in an arched frame like a portrait in a haunted hall. */
.looks {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 96px); /* a fourth look shrinks them to fit a phone */
  justify-content: center;
  gap: 16px;
  margin-top: 8px;
}

.look {
  appearance: none;
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--fog);
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
}

.look img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 50% 50% 14px 14px / 40% 40% 14px 14px;
  background: var(--dusk);
  transition: transform 180ms ease, box-shadow 180ms ease;
}

.look[aria-pressed="true"] { color: var(--sheet); font-weight: 700; }
.look[aria-pressed="true"] img { outline: 2.5px solid var(--pumpkin); outline-offset: 3px; }

/* A portrait leans out of its frame toward the mouse, lit by a candle. Picking one
   possesses it for a moment (app.ts). */
@media (hover: hover) {
  .look:hover img { transform: translateY(-4px) rotate(-1.5deg); box-shadow: 0 10px 24px rgb(255 106 19 / 0.3); }
  .look:nth-child(even):hover img { transform: translateY(-4px) rotate(1.5deg); }
}

/* Jack-o'-lanterns on the floor beside the picture, under the looks, where there's room.
   Their candles flicker; a mouse over one makes it rock and flare. */
.lanterns { display: none; justify-content: center; align-items: flex-end; margin-top: auto; padding-top: 12px; }
.lanterns img { display: block; height: auto; transform-origin: 50% 90%; animation: candle 3.4s linear infinite; }
.lanterns .big { width: 100px; }
.lanterns .small { width: 74px; margin-left: -22px; animation-delay: -1.7s; }
.lanterns img:hover { animation: candle 3.4s linear infinite, rock 0.7s ease-in-out; }

.go,
.scare,
.add {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 54px;
  padding: 0 28px;
  border: 0;
  border-radius: 999px;
  font: inherit;
  font-size: 18px;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition: transform 120ms ease, background-color 160ms ease, box-shadow 160ms ease;
}

.go { background: var(--pumpkin); color: var(--night); }
/* Night, nearly opaque, so it reads over a bright ghost too. */
.go[aria-pressed="true"] { background: rgb(23 17 42 / 0.78); color: var(--sheet); box-shadow: inset 0 0 0 1.5px rgb(242 237 251 / 0.32); }

/* The jump scare: a black hole of a button whose label is torn like the scare itself. */
.scare { background: var(--hole); color: var(--sheet); box-shadow: inset 0 0 0 1px var(--line); }
.scare-label { display: inline-block; text-shadow: -1.5px 0 #ff2a3d, 1.5px 0 #19dfff; }

/* Once the ghost is ready, Haunt me pulses until it's pressed: it's the next thing to do. */
.go.invite { animation: invite 1.8s ease-out infinite; }

@media (hover: hover) {
  .go:hover { background: #ff7d33; box-shadow: 0 0 26px rgb(255 106 19 / 0.45); }
  .go[aria-pressed="true"]:hover { background: rgb(23 17 42 / 0.78); box-shadow: inset 0 0 0 1.5px rgb(242 237 251 / 0.6); }
  .scare:hover .scare-label { animation: jitter 300ms steps(1) 2; }
}

.scare:focus-visible .scare-label { animation: jitter 300ms steps(1) 2; }

.go:active,
.scare:active,
.add:active { transform: scale(0.97); }

.go:disabled,
.scare:disabled {
  cursor: default;
  background: rgb(242 237 251 / 0.07);
  color: rgb(242 237 251 / 0.34);
  box-shadow: none;
  transform: none;
}

.scare:disabled .scare-label { text-shadow: none; animation: none; }

/* The install button stands on the graveyard at the foot of the page, centered on the page
   rather than under the picture: the way out of the try-it room. A tall window puts its
   extra room above the button, so the button stays on the graveyard. Close enough under
   the picture that its top shows in a laptop's first screen, a hint to scroll. */
.home { display: flex; flex-direction: column; padding-bottom: 20px; }
.get { margin-top: auto; padding-top: 40px; text-align: center; }

h2 {
  margin: 0 0 24px;
  color: var(--sheet);
  font-family: var(--display);
  font-size: clamp(36px, 6.4vw, 50px);
  font-weight: 800;
  line-height: 1;
}

/* Taking the ghost home isn't one of the try-it controls: it glows in the ghost's own white
   instead of pumpkin, and carries the Haunt Cam icon that will sit in Chrome's toolbar. */
.add {
  min-height: 62px;
  gap: 12px;
  padding: 0 32px 0 16px;
  background: var(--sheet);
  color: var(--night);
  font-size: 20px;
  box-shadow: 0 0 0 6px rgb(242 237 251 / 0.08), 0 0 40px rgb(242 237 251 / 0.22);
}

.add-icon { width: 32px; height: 32px; transition: transform 220ms ease; }

@media (hover: hover) {
  .add:hover { box-shadow: 0 0 0 8px rgb(242 237 251 / 0.12), 0 0 56px rgb(242 237 251 / 0.36); }
  .add:hover .add-icon { transform: translateY(-2px) rotate(-8deg); }
}

/* The foot of the page is a graveyard; a phone sees its middle, the house. */
.ground { line-height: 0; }
.ground picture { display: block; }

.ground img {
  display: block;
  width: 100%;
  height: clamp(150px, 16.7vw, 260px);
  object-fit: cover;
  object-position: 50% 100%;
}

/* The footer stands on the ground, lined up with the page above it. */
.footer {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 6px max(var(--gutter), calc((100% - 1320px) / 2 + var(--gutter))) max(28px, env(safe-area-inset-bottom));
  background: var(--ink);
  color: var(--fog);
  font-size: 15px;
}

.footer p { margin: 0; }

.credit { color: var(--sheet); text-decoration: none; }
.credit span { text-decoration: underline; text-underline-offset: 3px; }
.x-logo { width: 0.85em; height: 0.85em; vertical-align: -0.08em; }

/* The privacy page. */
.doc { max-width: 680px; }
.doc h1 { margin-top: 18px; font-size: clamp(52px, 10vw, 76px); text-align: left; }
.doc .lede { margin: 16px 0 32px; color: var(--fog); font-size: clamp(19px, 2.4vw, 22px); line-height: 1.4; text-wrap: pretty; }
.doc h2 { margin: 36px 0 8px; font-size: 30px; }
.doc p,
.doc li { max-width: 62ch; }
.doc ul { padding-left: 1.2em; }

@media (max-width: 719px) {
  .lights { height: 46px; background-size: 200px 46px; }
  /* No margins to hang in: they would cross the title. */
  .spider,
  .moon { display: none; }
  .stage { max-height: 68svh; } /* a phone's camera may be portrait; svh leaves Safari's toolbars out */
  .actions .go,
  .actions .scare { flex: 1; padding: 0 16px; }
}

@media (min-width: 720px) {
  :root { --gutter: 32px; }
  .page { padding-top: 62px; }
  .stage { border-radius: 28px; transition: aspect-ratio 500ms ease; }
}

/* A tablet stacks the looks and controls under the picture, so the picture leaves them room. */
@media (min-width: 720px) and (max-width: 959px) {
  .theater { max-width: max(560px, calc((100svh - 540px) * var(--ratio))); margin-inline: auto; }
}

/* A laptop puts the looks and the controls in a panel beside the picture, like Meet's
   effects panel, and sizes the picture by the window's height: 160px above it for the
   title, 133px under it for the status row and the top of the install section. */
@media (min-width: 960px) {
  .page { padding-top: clamp(52px, 8svh, 62px); }
  /* A short window gets a smaller title, so the install section still peeks in. */
  h1 { font-size: clamp(54px, min(5.4vw, 9.6svh), 76px); line-height: 1; }
  .hero {
    display: grid;
    grid-template-columns: minmax(0, calc(max(315px, 100svh - 293px) * var(--ratio))) clamp(200px, 30svh, 240px);
    justify-content: center;
    column-gap: 28px;
  }
  .side { display: flex; flex-direction: column; }
  .looks { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 16px; margin-top: 0; }
  .actions { flex-direction: column; margin-top: 22px; }
  .get { padding-top: 32px; }
}

@media (min-width: 960px) and (min-height: 780px) {
  .lanterns { display: flex; }
}

/* The spider rides its thread up and down a little. */
@keyframes dangle {
  from { transform: translateY(0); }
  to { transform: translateY(14px); }
}

/* Candlelight inside the pumpkins. */
@keyframes candle {
  0%, 100% { filter: brightness(1); }
  18% { filter: brightness(1.07); }
  31% { filter: brightness(0.95); }
  47% { filter: brightness(1.04); }
  63% { filter: brightness(0.97); }
  81% { filter: brightness(1.06); }
}

/* The idle ghost: it floats up and its shadow shrinks; it blinks now and then. */
@keyframes hover { to { transform: translateY(-6px); } }
@keyframes shadow { to { transform: scaleX(0.76); opacity: 0.18; } }
@keyframes blink {
  0%, 92%, 100% { transform: scaleY(1); }
  94% { transform: scaleY(0.1); }
}

/* Bats: across the sky, then off screen until the next pass. */
@keyframes fly {
  from { transform: translateX(-80px); }
  45%, to { transform: translateX(calc(100vw + 80px)); }
}
@keyframes fly-back {
  from { transform: translateX(calc(100vw + 80px)); }
  45%, to { transform: translateX(-80px); }
}
@keyframes bob { to { transform: translateY(24px); } }
@keyframes flap { to { transform: scaleY(0.35); } }

@keyframes invite {
  from { box-shadow: 0 0 0 0 rgb(255 106 19 / 0.55); }
  to { box-shadow: 0 0 0 16px rgb(255 106 19 / 0); }
}

/* A pumpkin rocks on its base, its candle flaring. */
@keyframes rock {
  0%, 100% { transform: rotate(0); filter: brightness(1); }
  25% { transform: rotate(-7deg); filter: brightness(1.35); }
  55% { transform: rotate(5deg); filter: brightness(1.2); }
  80% { transform: rotate(-2deg); }
}

/* An old bulb catching: a few hard flickers, then steady. */
@keyframes catch {
  0% { opacity: 0; }
  10% { opacity: 0.75; }
  16% { opacity: 0.08; }
  28% { opacity: 0.9; }
  33% { opacity: 0.3; }
  46% { opacity: 1; }
  52% { opacity: 0.55; }
  60%, 100% { opacity: 1; }
}

@keyframes jitter {
  0% { transform: translate(-1px, 0.5px); text-shadow: -3px 0 #ff2a3d, 2px 0 #19dfff; }
  25% { transform: translate(1.5px, -0.5px); text-shadow: 2px 0 #ff2a3d, -3px 0 #19dfff; }
  50% { transform: translate(-0.5px, -1px); text-shadow: -2px 1px #ff2a3d, 2px -1px #19dfff; }
  75% { transform: translate(1px, 1px); text-shadow: -4px 0 #ff2a3d, 1px 0 #19dfff; }
  100% { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  h1,
  .lights,
  .spider,
  .ghost-body,
  .ghost-shadow,
  .ghost-eye,
  .lanterns img,
  .go.invite,
  .scare-label { animation: none !important; }
  .lights { background-image: url("decor/lights.svg"); }
  .flight { display: none; }
  .go,
  .scare,
  .stage,
  .stage-ghost,
  .look img,
  .add-icon,
  .glow { transition: none; }
}
