/* Rainbow Universe: the sky with every game as an island, the Puff, the hatch, the Home Cloud and the game frame.
   The storybook look (round glass buttons, curtain, clouds, names on the sky) comes from assets/storybook.css. */
.scene { background-image: url(../assets/art/ui/sky.webp); }
@media (orientation: landscape) { .scene { background-image: url(../assets/art/ui/sky-wide.webp); } }
.sky, .picker, .hatch, .homecloud, .cart { position: fixed; inset: 0; }
@property --a { syntax: '<angle>'; inherits: true; initial-value: 0deg; }

/* ---------- the sky ---------- */
/* The rainbow is the progress meter: it grows across the sky, stripe by stripe (7 to a full rainbow). The unlit part
   is a pale ghost of the same picture, so the whole arch is always there to look forward to. */
/* The stage: the rainbow, the islands, the Puff and the present are laid out on one stage per kind of screen
   (sideways 16:9, an upright tablet 4:5, an upright phone 1:2), scaled to fit the screen and standing on its bottom,
   so nothing ever overlaps or shrinks to a dot; the sky and its clouds fill whatever is left around it. Sizes inside
   are in stage units (cqw/cqh). */
.stage {
  --ar: 16 / 9;
  position: absolute;
  left: 50%;
  bottom: 0;
  translate: -50% 0;
  aspect-ratio: var(--ar);
  width: min(100vw, 100vh * 16 / 9);
  container-type: size;
  z-index: 2;
}
@media (max-aspect-ratio: 5 / 4) { .stage { --ar: 4 / 5; width: min(100vw, 100vh * 4 / 5); } }
@media (max-aspect-ratio: 7 / 10) { .stage { --ar: 1 / 2; width: min(100vw, 100vh / 2); } }
.rainbow {
  position: absolute;
  left: 50%;
  top: 1cqh;
  width: 60cqw;
  aspect-ratio: 1887 / 1181;
  translate: -50% 0;
  pointer-events: none;
  transition: --a 1.8s cubic-bezier(.4, 0, .2, 1);
}
.rainbow img { position: absolute; inset: 0; width: 100%; height: 100%; }
.rainbow .ghost { opacity: .2; filter: saturate(.3) brightness(1.35); }
.rainbow .lit {
  -webkit-mask: conic-gradient(from -90deg at 50% 100%, #000 var(--a), transparent calc(var(--a) + .5deg));
  mask: conic-gradient(from -90deg at 50% 100%, #000 var(--a), transparent calc(var(--a) + .5deg));
  filter: drop-shadow(0 6px 10px rgba(150, 110, 200, .25));
}
.rainbow.full .lit { animation: shimmer 1.6s ease-in-out 2; }
@keyframes shimmer { 50% { filter: drop-shadow(0 0 22px #fff6c8) brightness(1.15); } }
@media (max-aspect-ratio: 5 / 4) { .rainbow { width: 92cqw; top: 3cqh; } }
@media (max-aspect-ratio: 7 / 10) { .rainbow { width: 100cqw; top: 6cqh; } }

/* depth: a finger dragging the sky (or the tablet tilting) sets --px/--py; near things move more than far ones, and
   everything springs back when the finger lets go */
.sky { --px: 0px; --py: 0px; }
.rainbow { transform: translate(calc(var(--px) * .3), calc(var(--py) * .3)); }
.isles { transform: translate(var(--px), var(--py)); }
.sky > .clouds { transform: translate(calc(var(--px) * 1.4), calc(var(--py) * 1.2)); }
.sky .rainbow { transition: --a 1.8s cubic-bezier(.4, 0, .2, 1), transform .9s cubic-bezier(.3, 1.5, .5, 1); }
.sky .isles, .sky > .clouds, .drift .cloud { transition: transform .9s cubic-bezier(.3, 1.5, .5, 1), translate .9s cubic-bezier(.3, 1.5, .5, 1); }
.sky.dragging .rainbow, .sky.dragging .isles, .sky.dragging > .clouds, .sky.dragging .drift .cloud { transition-duration: 1.8s, .08s; }
.sky.dragging .isles, .sky.dragging > .clouds { transition-duration: .08s; }

/* the retina cloud bank (5600 x 1050, 4x upscaled) in place of the games' older one: the sky's low clouds and the curtain */
.clouds { --cloud-h: calc(112vw * 1050 / 5600); background-image: url(../assets/art/ui/cloudbank.webp); will-change: translate; }
/* the curtain: this bank is puffy on every side, so each layer reaches further past the screen edge (no strip of sky
   when the curtain is closed) */
.curtain .cl { will-change: transform; }
.curtain .cl.low, .curtain .cl.low.back { bottom: -12vh; }
.curtain .cl.high, .curtain .cl.high.back { top: -12vh; }
.curtain .cl.low, .curtain .cl.high { height: 76vh; }
.curtain .cl.low.back, .curtain .cl.high.back { height: 90vh; }

/* clouds drifting across: far ones behind the islands, near ones low in front */
.drift { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.drift .cloud { position: absolute; left: 0; height: auto; animation: cross var(--t) linear infinite; pointer-events: auto; will-change: transform; }   /* tap a cloud: it sprinkles */
.drift .cloud.back { z-index: 1; opacity: .72; translate: calc(var(--px) * .6) calc(var(--py) * .6); }
.drift .cloud.front { z-index: 3; opacity: .78; pointer-events: none;   /* (never over the dragon: a tap there is for it) */ translate: calc(var(--px) * 1.9) calc(var(--py) * 1.6); }
@keyframes cross { from { transform: translateX(-50vmin); } to { transform: translateX(calc(100vw + 10vmin)); } }
@media (prefers-reduced-motion: reduce) { .drift { display: none; } }

/* a butterfly visiting (a Dress Up sticker, fluttering) */
.butterfly { position: absolute; left: 0; top: 0; z-index: 3; will-change: transform; width: clamp(44px, 7vmin, 80px); translate: -50% -50%; }
.butterfly img { width: 100%; display: block; animation: flap .28s ease-in-out infinite alternate; filter: drop-shadow(0 6px 6px rgba(110, 80, 180, .25)); }
@keyframes flap { from { transform: scaleX(1) rotate(-4deg); } to { transform: scaleX(.55) rotate(4deg); } }

/* Nimbus glides across the far sky now and then */
.nimbus {
  position: absolute;
  top: 17%;
  left: 0;
  width: clamp(120px, 20vmin, 230px);
  translate: 110vw 0;
  animation: glide 70s linear infinite;
  animation-delay: -18s;
  z-index: 1;
}
.nimbus { transform: translate(calc(var(--px) * .45), calc(var(--py) * .45)); }
.nimbus img { width: 100%; display: block; animation: float 5s ease-in-out infinite; filter: drop-shadow(0 12px 14px rgba(120, 90, 190, .2)); }
.nimbus.sing img { animation: sing 1.4s ease-in-out; }
@keyframes glide { from { translate: 110vw 0; } to { translate: -40vw 4vh; } }
@keyframes sing { 30% { transform: scale(1.12) rotate(-6deg); } 60% { transform: scale(.96) rotate(3deg); } }
@media (orientation: portrait) { .nimbus { top: 30%; } }

/* islands: positions per screen shape (x and y of the island's middle, width) */
.isles { position: absolute; inset: 0; z-index: 2; }
.isle {
  --w: 22cqw;
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  transform: translate(-50%, -50%);   /* not `translate`: the float animation uses that one */
  display: flex;
  flex-direction: column;
  align-items: center;
  animation: float 6s ease-in-out infinite;
  animation-delay: var(--d, 0s);
}
.isle img { width: 100%; height: auto; display: block; filter: drop-shadow(0 16px 18px rgba(110, 80, 180, .28)); transition: scale .2s; }
.isle:active img { scale: .94; }
.isle .name {
  margin-top: -.3em;
  color: var(--c);
  font-weight: 900;
  font-size: clamp(14px, calc(var(--w) * .12), 40px);
  line-height: 1;
  white-space: nowrap;
  -webkit-text-stroke: .3em #fff;
  paint-order: stroke fill;
  filter: drop-shadow(0 3px 4px rgba(124, 111, 208, .35));
}
.isle.soon { pointer-events: auto; }
.isle.soon img { filter: blur(1.2px) saturate(.5) brightness(1.08) opacity(.62); }
.isle.soon::after {   /* soft mist around an island still to come */
  content: "";
  position: absolute;
  inset: -12% -18%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 255, 255, .78), rgba(255, 255, 255, .35) 55%, rgba(255, 255, 255, 0));
  pointer-events: none;
}
.isle.glow img { animation: glow 1.6s ease-in-out infinite alternate; }
@keyframes glow { to { filter: drop-shadow(0 0 20px #fff6b8) drop-shadow(0 16px 18px rgba(110, 80, 180, .28)) brightness(1.08); } }
.isle.home .name { display: none; }

/* sideways (16:9): the five islands in a gentle arc under the rainbow */
.isle[data-id="memory-match"] { --x: 14%; --y: 60%; --w: 19cqw; --d: -1s; }
.isle[data-id="finger-paint"] { --x: 31%; --y: 35%; --w: 16.5cqw; --d: -3s; }
.isle[data-id="home"]         { --x: 50%; --y: 68%; --w: 19cqw; --d: -2s; }
.isle[data-id="dress-up"]     { --x: 69%; --y: 35%; --w: 16.5cqw; --d: -4s; }
.isle[data-id="shape-sorter"] { --x: 86%; --y: 60%; --w: 19cqw; --d: -5s; }
.isle[data-id="balloon-pop"]  { --x: 6%;  --y: 18%; --w: 9cqw; --d: -2.5s; }
.isle[data-id="animal-piano"] { --x: 94%; --y: 18%; --w: 10cqw; --d: -1.5s; }
.isle[data-id="count-with-me"]{ --x: 50%; --y: 14%; --w: 9cqw; --d: -3.5s; }
/* an upright tablet (4:5) */
@media (max-aspect-ratio: 5 / 4) {
  .isle[data-id="memory-match"] { --x: 25%; --y: 35%; --w: 33cqw; }
  .isle[data-id="finger-paint"] { --x: 75%; --y: 34%; --w: 30cqw; }
  .isle[data-id="home"]         { --x: 50%; --y: 61%; --w: 30cqw; }
  .isle[data-id="dress-up"]     { --x: 23%; --y: 82%; --w: 31cqw; }
  .isle[data-id="shape-sorter"] { --x: 77%; --y: 83%; --w: 33cqw; }
  .isle[data-id="balloon-pop"]  { --x: 10%; --y: 12%; --w: 14cqw; }
  .isle[data-id="animal-piano"] { --x: 90%; --y: 12%; --w: 15cqw; }
  .isle[data-id="count-with-me"]{ --x: 50%; --y: 17%; --w: 13cqw; }
}
/* an upright phone (1:2) */
@media (max-aspect-ratio: 7 / 10) {
  .isle[data-id="memory-match"] { --x: 26%; --y: 32%; --w: 42cqw; }
  .isle[data-id="finger-paint"] { --x: 75%; --y: 31%; --w: 39cqw; }
  .isle[data-id="home"]         { --x: 50%; --y: 54%; --w: 42cqw; }
  .isle[data-id="dress-up"]     { --x: 25%; --y: 76%; --w: 39cqw; }
  .isle[data-id="shape-sorter"] { --x: 75%; --y: 77%; --w: 42cqw; }
  .isle[data-id="balloon-pop"]  { --x: 12%; --y: 13%; --w: 18cqw; }
  .isle[data-id="animal-piano"] { --x: 88%; --y: 13%; --w: 20cqw; }
  .isle[data-id="count-with-me"]{ --x: 50%; --y: 19%; --w: 17cqw; }
}

/* the child's Puff, sitting on the clouds in front of home */
.sky-puff {
  position: absolute;
  left: 50%;
  bottom: calc(var(--safe-b) + 1.5cqh);
  width: 30cqw;   /* (the dragon's frame has room for its spread wings: the dragon itself is about half of it) */
  translate: -50% 0;
  z-index: 4;
  /* depth by margin: its transform belongs to the flight */
  margin-left: calc(var(--px) * 1.3);
  margin-bottom: calc(var(--py) * -1.1);
  transition: margin .9s cubic-bezier(.3, 1.5, .5, 1);
}
.sky.dragging .sky-puff { transition-duration: .08s; }
.sky-puff img, .puff-img { width: 100%; display: block; will-change: transform; filter: drop-shadow(0 10px 10px rgba(110, 80, 180, .3)); transform-origin: 50% 95%; }
.sky-puff img { animation: breathe 3.6s ease-in-out infinite; }
.sky-puff.giggle img, .puff-img.giggle { animation: giggle .9s ease-in-out; }
.sky-puff.hop img { animation: hop .7s cubic-bezier(.3, 1.4, .5, 1); }
@keyframes breathe { 0%, 100% { scale: 1 1; } 50% { scale: 1.025 .975; } }
@keyframes giggle { 20% { rotate: -9deg; scale: 1.06 .94; } 45% { rotate: 8deg; scale: .96 1.05; } 70% { rotate: -4deg; } }
@keyframes hop { 40% { translate: 0 -22%; scale: .94 1.08; } 70% { translate: 0 0; scale: 1.08 .93; } }
@media (min-aspect-ratio: 5 / 4) { .sky-puff { left: 32%; width: 14.5cqw; bottom: calc(var(--safe-b) + 1cqh); } }
@media (max-aspect-ratio: 5 / 4) and (min-aspect-ratio: 7 / 10) { .sky-puff { width: 23cqw; } }

/* a present from the end of the rainbow */
.gift { position: absolute; z-index: 5; width: 9cqw; left: 64%; bottom: calc(var(--safe-b) + 3cqh); }
@media (max-aspect-ratio: 5 / 4) { .gift { width: 17cqw; left: 66%; } }
.gift img { width: 100%; display: block; filter: drop-shadow(0 10px 12px rgba(110, 80, 180, .35)); animation: wiggle 2.2s ease-in-out infinite; }
.gift.drop { animation: drop 1.3s cubic-bezier(.3, 1.3, .5, 1) both; }
@keyframes drop { from { translate: 20vw -80vh; rotate: 30deg; } to { translate: 0 0; rotate: 0deg; } }
@keyframes wiggle { 0%, 70%, 100% { rotate: 0deg; } 76% { rotate: -8deg; } 84% { rotate: 7deg; } 92% { rotate: -3deg; } }
.reveal { position: fixed; z-index: 70; left: 50%; top: 50%; width: min(46vmin, 300px); translate: -50% -50%; pointer-events: none; }
.reveal img { width: 100%; display: block; filter: drop-shadow(0 16px 18px rgba(59, 35, 82, .35)); }
.reveal .rays { position: absolute; inset: -35%; border-radius: 50%; animation: rays 6s linear infinite; z-index: -1;
  background: repeating-conic-gradient(rgba(255, 244, 190, .75) 0 10deg, rgba(255, 244, 190, 0) 10deg 24deg);
  -webkit-mask: radial-gradient(circle, #000 30%, transparent 68%); mask: radial-gradient(circle, #000 30%, transparent 68%); }
@keyframes rays { to { rotate: 360deg; } }

/* ---------- who's playing ---------- */
.puffs { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: 6vmin; flex-wrap: wrap; padding: 8vh 6vw 20vh; }
.pick { position: relative; width: clamp(110px, 24vmin, 230px); animation: float 5s ease-in-out infinite; animation-delay: var(--d, 0s); }
.pick .perch { position: absolute; left: -10%; right: -10%; bottom: -12%; height: 34%; background: url(../assets/art/ui/cloud-seat.webp) center / contain no-repeat; }
.pick img { position: relative; width: 100%; display: block; filter: drop-shadow(0 10px 10px rgba(110, 80, 180, .3)); }
.pick:active img { scale: .94; }


/* ---------- the Home Cloud ---------- */
/* The room picture keeps its shape (1.75 : 1) and covers the screen; things are placed in % of the picture.
   On a tall screen the room is shown wide enough to keep both walls of shelves, and the cushioned wall continues
   above and below it. */
.homecloud { background: linear-gradient(#e9c7d9, #e6c2d6 60%, #ddb7cf); overflow: hidden; }
/* the room stands on the bottom of the screen: when it's cropped, the ceiling goes, never the floor */
.room { position: absolute; left: 50%; bottom: 0; aspect-ratio: 1344 / 768; width: max(100vw, 175vh); translate: -50% 0; }
/* upright: the whole width of the tall room, standing on the bottom of the screen; on a very narrow phone the cloud
   ceiling continues above it (the section's own gradient) */
/* upright: the tall room covers the screen (on a narrow phone its outer walls are cropped a little: the shelves' spots
   sit inward, js/home.js) */
.room.tall { aspect-ratio: 768 / 1344; width: max(100vw, 57.2vh); }
.room .bg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.things { position: absolute; inset: 0; }
.thing { position: absolute; translate: -50% -100%; transform-origin: 50% 100%; touch-action: none; }
/* picked up in the playroom: lifted a little bigger, above everything */
.thing.held { z-index: 30; scale: 1.15; }
.thing.held img { filter: drop-shadow(0 22px 14px rgba(90, 50, 110, .3)); }
.thing img { width: 100%; display: block; filter: drop-shadow(0 6px 5px rgba(90, 50, 110, .28)); }
.thing.toy { width: 5.6%; }
.thing.toy.new img, .thing.frame.new, .thing.pet.new img { animation: newest 1.4s ease-in-out 4; }
@keyframes newest { 50% { scale: 1.1; filter: drop-shadow(0 0 14px rgba(255, 214, 92, .95)); } }
.thing.toy.missing img { filter: brightness(0) invert(1) opacity(.38) drop-shadow(0 2px 3px rgba(150, 90, 140, .15)); }
.thing.toy:active img { animation: giggle .6s; }
.thing.frame { width: 8.4%; aspect-ratio: 507 / 512; translate: -50% -50%; }
.thing.frame .pic { position: absolute; inset: 13%; object-fit: cover; width: 74%; height: 74%; border-radius: 3px; background: #fff; }
.thing.frame .fr { position: absolute; inset: 0; width: 100%; height: 100%; filter: drop-shadow(0 5px 5px rgba(90, 50, 110, .28)); }
.thing.pet { width: 8%; }
.thing.pet img { animation: breathe 3s ease-in-out infinite; }
.thing.puff { width: 18%; }
.room .window-spot { position: absolute; left: 49%; top: 44%; width: 22%; aspect-ratio: 1; translate: -50% -50%; border-radius: 50%; }

/* ---------- a game in the universe ---------- */
.cart { background: #e6dcff; z-index: 10; }
.frame-host, .frame-host iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }
/* the way back to the sky, only while the game shows its islands (its own home button isn't there): the same round
   house button the games use for "up one level", in the same corner */
.cart-back { position: fixed; z-index: 30; top: calc(var(--safe-t) + 10px); left: calc(var(--safe-l) + 10px); animation: pop-in .5s cubic-bezier(.3, 1.6, .5, 1); }
@keyframes pop-in { from { scale: 0; } }
/* the child's Puff sits on the clouds of every game's islands, like it sits on the clouds of the sky */
.cart-puff { position: fixed; z-index: 30; left: calc(var(--safe-l) + 2.5vmin); bottom: calc(var(--safe-b) + .5vh); width: clamp(84px, 16vmin, 190px);
  animation: pop-in .6s cubic-bezier(.3, 1.6, .5, 1); }
.cart-puff img { width: 100%; display: block; transform-origin: 50% 95%; animation: breathe 3.6s ease-in-out infinite; filter: drop-shadow(0 10px 10px rgba(110, 80, 180, .3)); }
/* the Puff pops up in a corner to cheer when the child wins something, then goes again */
.cheer { position: fixed; z-index: 31; right: calc(var(--safe-r) + 2vmin); bottom: 0; width: clamp(80px, 14vmin, 150px); pointer-events: none;
  translate: 0 110%; transition: translate .5s cubic-bezier(.3, 1.4, .5, 1); }
.cheer img { width: 100%; display: block; filter: drop-shadow(0 8px 10px rgba(110, 80, 180, .35)); transform-origin: 50% 100%; }
.cheer.on { translate: 0 18%; }
.cheer.on img { animation: hop .7s cubic-bezier(.3, 1.4, .5, 1) .3s 2; }

/* ---------- grown-ups ---------- */
.sheet .puff-row { display: flex; gap: 10px; margin: 6px 0 2px; }
.sheet .puff-row img { width: 54px; }
