/* Creature Lab: one committed look, a cave workshop lit by its own crystals.
   There is no light theme on purpose, and every colour is painted explicitly so
   the page never borrows a host background. */

:root {
  --ink:        #07040f;
  --rock-far:   #1b1235;
  --rock:       #241847;
  --rock-lit:   #32215f;
  --rock-edge:  #45307d;
  --rock-fore:  #120b26;
  --niche:      #150d2c;

  --pool:       #3ad6b0;
  --crystal-a:  #7ee0ff;
  --crystal-b:  #c08cff;
  --lamp:       #ffc46b;
  --magic:      #6fe3ae;

  --parchment:  #f2e6d2;
  --muted:      #9c8dc2;

  --display: 'Grandstander', 'Trebuchet MS', Verdana, sans-serif;
  --ui: 'Lexend', 'Avenir Next', 'Segoe UI', system-ui, sans-serif;

  color-scheme: dark;
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--parchment);
  font-family: var(--ui);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior: none;
  touch-action: manipulation;
  overflow: hidden;
}

button { font: inherit; color: inherit; border: 0; background: none; cursor: pointer; }
:focus-visible { outline: 3px solid var(--lamp); outline-offset: 3px; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --------------------------------------------------------------- the door */

#splash {
  position: fixed; inset: 0; z-index: 40;
  display: grid; place-items: center; padding: 24px;
  background:
    radial-gradient(58% 44% at 50% 30%, rgba(111, 227, 174, 0.14), transparent 70%),
    linear-gradient(180deg, var(--rock) 0%, var(--ink) 72%);
  transition: opacity 0.45s ease;
}
#splash.gone { opacity: 0; pointer-events: none; }
.splash-card { text-align: center; max-width: 440px; }
#splash h1 {
  font-family: var(--display); font-weight: 800;
  font-size: clamp(2.2rem, 8.5vw, 3.2rem);
  margin: 0 0 6px; letter-spacing: -0.5px; text-wrap: balance;
  text-shadow: 0 0 36px rgba(111, 227, 174, 0.45);
}
#splash p { margin: 0 0 28px; color: var(--muted); font-size: 1.05rem; }
.big-btn {
  font-family: var(--display); font-weight: 800; font-size: 1.2rem;
  padding: 16px 34px; border-radius: 999px; color: #10240f;
  background: linear-gradient(180deg, #9cf0c6, var(--magic));
  box-shadow: 0 10px 0 #2f8d67, 0 16px 38px rgba(111, 227, 174, 0.3);
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.big-btn:active { transform: translateY(6px); box-shadow: 0 4px 0 #2f8d67; }

/* -------------------------------------------------------------- the grotto */

#app { height: 100%; display: grid; grid-template-rows: auto minmax(0, 1fr); }

header {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 16px; padding-top: calc(10px + env(safe-area-inset-top, 0px));
  position: relative; z-index: 6;
}
.brand {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--display); font-weight: 800; font-size: 1.05rem;
}
.brand-drop {
  width: 13px; height: 17px; border-radius: 50% 50% 50% 50% / 62% 62% 38% 38%;
  transform: rotate(180deg);
  background: linear-gradient(180deg, var(--magic), #2fa97a);
  box-shadow: 0 0 14px rgba(111, 227, 174, 0.7);
}
.tool {
  width: 44px; height: 44px; border-radius: 14px; display: grid; place-items: center;
  font-size: 1.2rem; background: rgba(50, 33, 95, 0.7);
  border: 1px solid rgba(255, 255, 255, 0.1);
  transition: transform 0.12s ease;
}
.tool:active { transform: scale(0.93); }

#stage {
  position: relative; overflow: hidden;
  min-height: 0;
  /* Continues the cave behind the letterbox when the screen is not the scene's
     3:2, so the bands read as more rock rather than as empty bars. */
  background: linear-gradient(180deg, var(--rock-far) 0%, var(--rock) 48%, var(--ink) 100%);
}
#stage::after {
  content: ''; position: absolute; inset: 0; z-index: 7; pointer-events: none;
  background: radial-gradient(72% 76% at 50% 56%, transparent 42%, rgba(7, 4, 15, 0.55) 100%);
}

/* Every layer spans the whole stage, so any of them will swallow a tap meant for
   something on a layer beneath. Nothing in the scene is tappable except the props
   and the creature, and those opt back in. */
.layer {
  position: absolute; inset: 0;
  pointer-events: none;
  will-change: transform;
  transform: scale(1.04);          /* so a parallax shift never reveals an edge */
  transform-origin: 50% 50%;
}
/* An <svg> root takes pointer events across its whole box, painted or not, so the
   foreground layer was blocking every tap aimed at the bench beneath it. Only the
   props are tappable; the rest of the cave is scenery. */
.layer svg.grotto { width: 100%; height: 100%; display: block; pointer-events: none; }
.prop { pointer-events: auto; }

/* Stacking, back to front. The creature sits between bench and foreground. */
.layer-far      { z-index: 1; }
.layer-mid      { z-index: 2; }
.layer-bench    { z-index: 3; }
.layer-creature { z-index: 4; transform: none; }
.layer-fore     { z-index: 5; }

/* ------------------------------------------------------------------- rock */

.rock-far  { fill: var(--rock-lit); }
.rock-mid  { fill: var(--rock-edge); }
.rock-fore { fill: var(--rock-fore); }

.niche     { fill: var(--niche); }
.niche-lip { fill: var(--rock-edge); }

.crack { fill: none; stroke: rgba(255, 196, 107, 0.45); stroke-width: 5; stroke-linecap: round; }

.pool {
  fill: var(--pool); opacity: 0.55;
  filter: drop-shadow(0 0 22px var(--pool));
  animation: pool-breathe 7s ease-in-out infinite;
}
@keyframes pool-breathe { 50% { opacity: 0.75; } }

.crystal-body { fill: var(--crystal-a); opacity: 0.62; }
.crystal-face { fill: #ffffff; opacity: 0.4; }
.crystal.b .crystal-body { fill: var(--crystal-b); }
.crystal { filter: drop-shadow(0 0 14px currentColor); color: var(--crystal-a); }
.crystal.b { color: var(--crystal-b); }
.crystal.dim { opacity: 0.45; }

.bench-top    { fill: var(--rock-edge); }
.bench-leg    { fill: var(--rock-lit); }
.bench-shadow { fill: rgba(7, 4, 15, 0.45); }

/* ------------------------------------------------------------------ props */

.prop { cursor: pointer; transform-box: fill-box; transform-origin: 50% 100%; }
.prop image { transform-box: fill-box; transform-origin: 50% 100%; }
.prop-shadow { fill: rgba(7, 4, 15, 0.42); }
.prop:hover image { transform: translateY(-3px); }
.prop image { transition: transform 0.18s ease; }
.prop.poked image { animation: prop-poked 0.5s cubic-bezier(.34, 1.5, .5, 1); }
@keyframes prop-poked {
  30% { transform: translateY(-14px) rotate(-6deg); }
  60% { transform: translateY(-4px) rotate(4deg); }
}

/* The one prop that leads somewhere gets a light of its own. */
.prop-door image { filter: drop-shadow(0 0 16px rgba(201, 166, 255, 0.85)); }
.prop-door { animation: door-pulse 3.4s ease-in-out infinite; }
@keyframes door-pulse { 50% { opacity: 0.88; } }

/* ------------------------------------------------------------------ light */

/* The masks are pre-tinted in room.js, so these only place them and set how much
   light each one throws. Kept low: this is a cave, and the point of the crystals
   is that they are the brightest things in it. */
.glow {
  position: absolute; pointer-events: none; z-index: 6;
  mix-blend-mode: screen;
}
/* The cone mask is cut off square at the bottom of its own canvas, which reads as
   a pane of glass hanging in the air. Fade it out before it gets there. */
.glow-shaft {
  left: 44%; top: -34%; width: 38%; opacity: 0.26; transform: rotate(6deg);
  -webkit-mask-image: linear-gradient(to bottom, #000 0 46%, transparent 92%);
  mask-image: linear-gradient(to bottom, #000 0 46%, transparent 92%);
}
.glow-bench { left: 58%; top: 44%; width: 26%; opacity: 0.34; }
.glow-pool  { left: 2%;  top: 58%; width: 32%; opacity: 0.40; }

/* -------------------------------------------------------------- creature */

/* In front of the bench, not on it, with its feet into the foreground rock so it
   reads as standing on the cave floor.

   The frame has to be exactly the box preserveAspectRatio="meet" resolves the
   scene to, or the creature drifts out of the room. It is sized in JS by
   fitCreatureFrame(): aspect-ratio plus max-height does NOT clamp once the width
   is definite, so on a screen wider than 3:2 the frame ran past the bottom of the
   scene and the foreground rock buried the creature.

   The layer takes no pointer events. It sits above the bench, and as a plain div
   it swallowed every tap aimed at the potion flask. */
.layer-creature { display: block; pointer-events: none; }
.creature-frame { position: absolute; pointer-events: none; }
#creature {
  /* The feet sit 16.04% up the frame, where they always have. The canvas is
     26% of the frame wide, so 41.66% of it tall (940/880 x 3/2), and the feet
     are drawn 4.5% of the canvas above its bottom edge (FEET_Y in anchors.js). */
  position: absolute; bottom: calc(16.04% - 41.66% * 0.045); left: 0; right: 0; margin-inline: auto;
  pointer-events: auto;
  width: 26%; height: auto; display: block;
  cursor: pointer;
  filter: drop-shadow(0 10px 14px rgba(7, 4, 15, 0.7));
  animation: breathe 4.6s ease-in-out infinite;
  transform-origin: 50% 100%;
}
@keyframes breathe {
  50% { transform: scale(1.025, 0.975); }
}
#creature.hop { animation: hop 0.62s cubic-bezier(.3, 1.4, .5, 1); }
@keyframes hop {
  0%   { transform: scale(1, 1) translateY(0); }
  22%  { transform: scale(1.14, 0.84) translateY(0); }
  55%  { transform: scale(0.92, 1.12) translateY(-28px); }
  78%  { transform: scale(1.1, 0.9) translateY(0); }
  100% { transform: scale(1, 1) translateY(0); }
}
#creature.wiggle { animation: wiggle 0.7s ease-in-out; }
@keyframes wiggle {
  25% { transform: rotate(-5deg); }
  60% { transform: rotate(4deg); }
}

/* A burst over the creature: greeting her, or taking the gift. */
.creature-frame .sparkles { position: absolute; inset: 0; pointer-events: none; z-index: 2; }
.creature-frame .sparkles i {
  position: absolute; left: 50%; top: 62%;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--lamp);
  box-shadow: 0 0 10px var(--lamp);
  animation: room-spark 1s ease-out forwards;
}
@keyframes room-spark {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.3); }
  25%  { opacity: 1; }
  100% { opacity: 0; transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(1.2); }
}

/* A crystal left on the bench after a long absence. It is a hello, not a
   currency: tapping it pops it and nothing is counted. */
.gift {
  pointer-events: auto;
  /* On the cave floor, left of the creature. The bench has no gap wide enough:
     63% sat inside the potion flask's glow and 43% sat behind the creature. */
  position: absolute; left: 16%; bottom: 13%;
  width: 6%; padding: 0; line-height: 0;
  filter: drop-shadow(0 0 14px var(--crystal-a));
  animation: gift-in 0.6s cubic-bezier(.34, 1.5, .5, 1), gift-bob 3s ease-in-out 0.6s infinite;
}
.gift svg { width: 100%; height: auto; display: block; overflow: visible; }
.gift .crystal-body { fill: var(--crystal-a); opacity: 0.72; }
.gift .crystal-face { fill: #fff; opacity: 0.45; }
@keyframes gift-in { from { opacity: 0; transform: scale(0.3) translateY(14px); } }
@keyframes gift-bob { 50% { transform: translateY(-6px); } }
.gift.taken { animation: gift-taken 0.4s ease forwards; }
@keyframes gift-taken { to { opacity: 0; transform: scale(1.8) translateY(-20px); } }

/* ---------------------------------------------------------------- chrome */

.build {
  position: fixed; right: 7px; z-index: 45;
  bottom: calc(3px + env(safe-area-inset-bottom, 0px));
  font-size: 0.6rem; color: rgba(242, 230, 210, 0.22);
  font-variant-numeric: tabular-nums; pointer-events: none;
}

.toast {
  position: fixed; left: 50%; bottom: 8%; transform: translateX(-50%);
  z-index: 30; padding: 12px 22px; border-radius: 999px;
  background: rgba(21, 13, 44, 0.92); border: 1px solid rgba(255, 255, 255, 0.14);
  font-family: var(--display); font-weight: 700;
  box-shadow: 0 10px 30px rgba(7, 4, 15, 0.6);
  animation: toast-in 0.26s ease;
}
@keyframes toast-in { from { opacity: 0; transform: translate(-50%, 10px); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
