/* ───────────────────────────────────────────────────────────────
   Tandem — the painted day
   The sky, the four sets and their loops (partials/scene.php), and the
   mascot frame (mascot.js). Shared by the landing and the sign-in pages;
   the app's onboarding plates are rendered from this file too
   (scripts/render_scene_plates.mjs), so a change here shows everywhere.
   ─────────────────────────────────────────────────────────────── */

/* ── The stage ── */
.stage { position: fixed; inset: 0; z-index: 0; overflow: hidden; }
/* Darkens the day once the story is over and the page turns into reading. */
.stage::after {
  content: ''; position: absolute; inset: 0; z-index: 4; pointer-events: none;
  background: #120c22; opacity: calc(var(--dim, 0) * .7);
}

/* The sky behind every set. scene.js sets the colours and where the sun is. */
.sky {
  position: absolute; inset: 0;
  background: linear-gradient(var(--sky-top, #f7b98a), var(--sky-bottom, #fde7c8));
}
.stars {
  position: absolute; inset: 0; opacity: var(--night, 0);
  background-image:
    radial-gradient(2px 2px at 12% 18%, #fff 50%, #0000 51%),
    radial-gradient(1.5px 1.5px at 32% 8%, #fff 50%, #0000 51%),
    radial-gradient(2px 2px at 54% 22%, #fff 50%, #0000 51%),
    radial-gradient(1.5px 1.5px at 72% 12%, #fff 50%, #0000 51%),
    radial-gradient(2px 2px at 88% 26%, #fff 50%, #0000 51%),
    radial-gradient(1.5px 1.5px at 22% 34%, #fff 50%, #0000 51%),
    radial-gradient(1.5px 1.5px at 64% 36%, #fff 50%, #0000 51%),
    radial-gradient(2px 2px at 44% 4%, #fff 50%, #0000 51%);
  animation: twinkle 4s ease-in-out infinite alternate;
}
@keyframes twinkle { to { filter: brightness(.6); } }
.sun, .moon {
  position: absolute; width: 110px; height: 110px; margin: -55px 0 0 -55px; border-radius: 50%;
  left: var(--sun-x, 20%); top: var(--sun-y, 70%);
}
.sun {
  background: radial-gradient(circle, #fff6d8 0 38%, #ffd27a 60%, #ffd27a00 72%);
  opacity: calc(1 - var(--night, 0));
}
.moon {
  left: var(--moon-x, 80%); top: var(--moon-y, 18%); width: 70px; height: 70px; margin: -35px 0 0 -35px;
  background: radial-gradient(circle at 38% 38%, #fffbe8 0 55%, #e9e2c6 70%, #e9e2c600 72%);
  opacity: var(--night, 0);
}
.cloud {
  position: absolute; width: 220px; height: 60px; border-radius: 60px;
  background: var(--cloud, #fff8ee); opacity: .85;
  box-shadow: 40px -26px 0 6px var(--cloud, #fff8ee), 100px -14px 0 10px var(--cloud, #fff8ee);
  animation: drift linear infinite;
}
.cloud.c1 { top: 12%; animation-duration: 90s; animation-delay: -20s; }
.cloud.c2 { top: 24%; transform: scale(.7); animation-duration: 120s; animation-delay: -70s; opacity: .7; }
.cloud.c3 { top: 6%; transform: scale(.5); animation-duration: 150s; animation-delay: -110s; opacity: .6; }
@keyframes drift { from { left: -320px; } to { left: 110%; } }

/* Four sets side by side; scene.js slides the strip, one screen per set. */
.strip {
  position: absolute; inset: 0; display: flex; width: 400vw;
  transform: translate3d(calc(var(--cam, 0) * -100vw), 0, 0);
  will-change: transform;
}
.set { flex: 0 0 100vw; height: 100vh; }
.defs { position: absolute; }

/* Always-on motion, one loop per set. Transforms only. */
.loop-far { animation: slide 60s linear infinite; }
.loop-near { animation: slide 7s linear infinite; }
.loop-road { animation: slide-road 1.1s linear infinite; }
@keyframes slide { to { transform: translateX(-1600px); } }
@keyframes slide-road { to { transform: translateX(-200px); } }
.bob { animation: bob .5s ease-in-out infinite alternate; }
@keyframes bob { to { transform: translateY(-3px); } }
.wheel { transform-box: fill-box; transform-origin: center; animation: spin .45s linear infinite; }
@keyframes spin { to { transform: rotate(-360deg); } }
.puff { transform-box: fill-box; transform-origin: center; animation: puff 1.4s ease-out infinite; }
.puff.p2 { animation-delay: .7s; }
@keyframes puff { from { transform: translate(0, 0) scale(.6); opacity: .8; } to { transform: translate(-60px, -30px) scale(2.2); opacity: 0; } }

.snip-arm { transform-box: fill-box; transform-origin: 0% 100%; animation: snip-arm 1.6s ease-in-out infinite; }
@keyframes snip-arm { 50% { transform: rotate(-4deg) translate(4px, -3px); } }
.blade { transform-box: fill-box; transform-origin: 0% 50%; }
.blade.b1 { animation: blade-a .4s ease-in-out infinite alternate; }
.blade.b2 { animation: blade-b .4s ease-in-out infinite alternate; }
@keyframes blade-a { to { transform: rotate(14deg); } }
@keyframes blade-b { to { transform: rotate(-12deg); } }
.bit { animation: fall 1.8s ease-in infinite; }
.bit.h2 { animation-delay: .6s; } .bit.h3 { animation-delay: 1.2s; }
@keyframes fall { from { transform: translate(0, 0) rotate(0); opacity: 1; } to { transform: translate(-10px, 250px) rotate(180deg); opacity: 0; } }
.neon { animation: neon 5s infinite; }
@keyframes neon { 0%, 18%, 22%, 100% { opacity: 1; } 20% { opacity: .55; } }

.hammer-arm { transform-box: fill-box; transform-origin: 0% 30%; animation: hammer .7s cubic-bezier(.5, 0, .8, .4) infinite alternate; }
@keyframes hammer { from { transform: rotate(-26deg); } to { transform: rotate(8deg); } }
.tok { opacity: 0; animation: tok .7s steps(1) infinite alternate; }
@keyframes tok { 0% { opacity: 0; } 50% { opacity: 1; } }
.birds { animation: birds 14s linear infinite; }
@keyframes birds { from { transform: translate(-100px, 220px); } to { transform: translate(1700px, 120px); } }

.steam path { animation: steam 2.6s ease-in-out infinite; }
.steam .s2 { animation-delay: .8s; } .steam .s3 { animation-delay: 1.6s; }
@keyframes steam { 0% { opacity: 0; transform: translateY(8px); } 40% { opacity: .8; } 100% { opacity: 0; transform: translateY(-26px); } }

/* A phone that is ringing, and one that is on a call. */
.phone.ringing { animation: buzz .09s linear infinite alternate; }
.phone.ringing .screen { fill: #d4b8f5; }
.phone.answered .screen { fill: #1f7a55; }
@keyframes buzz { from { transform: translateX(-2px); } to { transform: translateX(2px); } }
.dinner-phone { transition: transform .8s cubic-bezier(.2, .8, .2, 1); }
.dinner-phone.at-ear { transform: translate(-12px, -150px) rotate(-70deg); transform-box: fill-box; transform-origin: center; }

/* ── Tandem (mascot.js) ── */
/* Zero specificity, so a page placing Tandem (absolute, on an edge) always wins. */
:where(.mascot) { position: relative; display: block; flex: none; }
.mascot[data-crop="head"] { border-radius: 50%; overflow: hidden; }
.mascot-draw { position: absolute; left: 0; top: 0; transition: opacity .2s cubic-bezier(.2, 0, 0, 1); }
.mascot-draw svg { display: block; }
/* A change of state: the new drawing fades in over the old (mascot.js). */
.mascot-draw.is-fading { opacity: 0; }
/* data-enter: the first time Tandem appears it steps up into place and
   settles with a small overshoot — decelerating in, like anything arriving. */
.mascot[data-enter] {
  opacity: 0; transform: translateY(14px);
  transition: opacity .24s ease-out, transform .4s cubic-bezier(.175, .885, .32, 1.275);
}
.mascot[data-enter].is-in { opacity: 1; transform: none; }
/* The landing hero is built from the logo instead (transform.js); the Lottie
   stays hidden until that hands over, then shows at once. */
.mascot[data-enter="logo"] { transform: none; transition: none; }
.mascot-transform { position: absolute; z-index: 40; pointer-events: none; will-change: transform; }
.mascot-transform svg { display: block; overflow: visible; }

/* Reduced motion: the day holds still. */
@media (prefers-reduced-motion: reduce) {
  .stage *, .stage *::before, .stage *::after { animation: none !important; transition: none !important; }
  .mascot-draw, .mascot[data-enter] { transition: none; }
}
