/* Moon -- phase display over a small city.
   Palette and layout only; scene.js paints the sky and skyline. */

:root{
  --ink:        #0f1320;
  --ink-lift:   #1b2233;
  --bone:       #f2ece0;
  --bone-dim:   #ddd3c0;
  --earthshine: #56658c;      /* the unlit face, lit by the Earth */
  --muted:      #79839c;
  --hair:       rgba(121,131,156,.22);
  /* three depth steps: distance washes contrast out and cools the hue,
     it does not only make things smaller */
  --town-far:   #10192c;
  --town-back:  #080e1c;
  --town-front: #020408;
  --wire:       #161c2b;
  --town-rim:   #3d4c6b;      /* moonlight catching the rooftops */
  --win:        #e0a355;
  --win-tv:     #7ea6d8;      /* one window with a television in it */

  /* Conservative default only. scene.js measures the text column and grows
     this to whatever is genuinely left over -- the column's height moves with
     the reader's font size, so any fixed reserve overlaps the skyline for
     somebody. This value is what you get if the script never runs. */
  --town-h: clamp(110px, 20vh, 190px);
  --moon-y: 0px;              /* reserved: real altitude above the roofline */

  /* the sky, blended toward twilight by the sun's real altitude */
  --sky-hi: #0f1320;
  --sky-lo: #141a2b;

  --serif: "Iowan Old Style","Palatino Linotype",Palatino,Georgia,"Times New Roman",serif;
  --sans: ui-sans-serif,-apple-system,"Segoe UI",Roboto,sans-serif;
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{height:100%}
body{
  margin:0;
  background:linear-gradient(to bottom, var(--sky-hi), var(--sky-lo));
  color:var(--bone);
  font-family:var(--sans);
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  padding:calc(env(safe-area-inset-top) + 24px) 24px calc(var(--town-h) + 16px);
  overflow:hidden;
}

/* The sky wheels very slowly around the moon, like a long exposure.
   scene.js sets left/top/width/height: the field has to be fitted to the
   farthest screen corner or the rotation drags bare patches into view. */
#sky{
  position:fixed;left:0;top:0;width:100%;height:100%;
  pointer-events:none;z-index:0;
}
.star{
  position:absolute;border-radius:50%;background:var(--bone);
  opacity:var(--o);will-change:opacity;
}
.star.lg{ box-shadow:0 0 4px 1px rgba(242,236,224,.30) }
@media (prefers-reduced-motion:no-preference){
  /* A sidereal day is the honest rate, but it is 0.06 deg over a ten-second
     glance -- which is to say invisible, and the sky may as well be a still.
     This is a stylised drift instead: perceptible if you watch, never a
     carousel. Raise it back toward 86164s for the true rate. */
  #sky{animation:wheel 1200s linear infinite}
  .star{animation:twinkle var(--dur) ease-in-out var(--delay) infinite}
}
@keyframes wheel{ to{ transform:rotate(360deg) } }
@keyframes twinkle{
  0%,100%{ opacity:calc(var(--o) * var(--amp, .55)) }
  50%    { opacity:var(--o) }
}

/* streetlight bleed: sits above the stars, below the buildings, and reaches
   higher than the band so tall shapes still read against a lifted sky */
#glow{
  position:fixed;left:-10%;bottom:0;width:120%;
  height:calc(var(--town-h) * 2.2);
  z-index:0;pointer-events:none;
  background:
    radial-gradient(ellipse 55% 48% at 50% 100%, rgba(235,182,112,.20), transparent 72%),
    radial-gradient(ellipse 95% 85% at 50% 100%, rgba(224,163,85,.11),  transparent 70%),
    radial-gradient(ellipse 120% 100% at 50% 100%, rgba(126,140,178,.13), transparent 75%);
}

/* town sits in front of the sky, so stars set behind the roofline */
#town{
  position:fixed;left:0;right:0;bottom:0;
  height:var(--town-h);
  pointer-events:none;z-index:2;
}
#town svg{display:block;width:100%;height:100%}
.win{ transition:opacity .7s ease }   /* a light switching on, not a dissolve */

.date,.moon-wrap,.name,.stats,.next,.foot{position:relative;z-index:1}

.date{
  font-size:11px;letter-spacing:.22em;text-transform:uppercase;
  color:var(--muted);margin-bottom:24px;
}

/* the bottom margin is headroom for the altitude offset, so a low moon never
   sinks into the heading */
.moon-wrap{ width:min(56vw,210px);aspect-ratio:1;margin-bottom:18px }
/* Altitude and apparent size live here, not on .moon-wrap, so the intro
   fade's own transform never overwrites them. */
.moon-pos{
  width:100%;height:100%;
  transform:translateY(var(--moon-y)) scale(var(--moon-scale,1));
  transition:transform .8s cubic-bezier(.22,.61,.36,1);
}
.moon-wrap svg{display:block;width:100%;height:100%;overflow:visible}
/* The disc turns for a southern view; animating it makes the button legible.
   transform-origin must be 0 0, not 50% 50%: this viewBox is centred on the
   origin (-128 -128 256 256), and a percentage resolves against the box size
   to user (128,128) -- a corner -- which flings the disc off the canvas. */
#disc{ transform-box:view-box;transform-origin:0 0;
       transition:transform .5s cubic-bezier(.22,.61,.36,1) }

.name{
  font-family:var(--serif);
  font-size:clamp(25px,7vw,32px);
  font-weight:400;letter-spacing:.005em;
  margin:30px 0 0;text-align:center;line-height:1.15;
}

.stats{
  margin-top:11px;
  font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted);text-align:center;
}

.detail{ margin-top:5px;opacity:.72 }

.next{
  margin-top:22px;padding-top:13px;
  border-top:1px solid var(--hair);
  font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted);text-align:center;min-width:180px;
}

.foot{margin-top:4px}
button{
  appearance:none;background:none;border:0;
  font-family:var(--sans);font-size:10px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted);padding:9px 14px;cursor:pointer;border-radius:2px;
}
button:hover{color:var(--bone-dim)}
button:focus-visible{outline:1px solid var(--muted);outline-offset:2px}

@media (prefers-reduced-motion:no-preference){
  .fade{animation:fade .7s ease both}
  @keyframes fade{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
}
@media (max-height:620px){
  .name{margin-top:20px}
  .next{margin-top:16px}
  .date{margin-bottom:16px}
}

@media (prefers-reduced-motion:reduce){
  .moon-pos,#disc{ transition:none }
}

/* A meteor: a short streak that stretches, then fades.
   The rotation has to live inside the keyframes -- an inline transform would
   simply be overridden by the animation -- and translateX after it moves the
   streak along its own axis, which is the direction it points. */
.meteor{
  position:fixed;z-index:0;pointer-events:none;
  height:1px;border-radius:1px;opacity:0;
  transform-origin:0 50%;
  background:linear-gradient(to right, rgba(242,236,224,0), rgba(242,236,224,.9));
}
@media (prefers-reduced-motion:no-preference){
  .meteor{animation:streak var(--dur,.7s) cubic-bezier(.4,0,.85,.4) forwards}
}
@keyframes streak{
  0%  {opacity:0;  transform:rotate(var(--rot)) translateX(0) scaleX(.15)}
  15% {opacity:.9}
  70% {opacity:.75}
  100%{opacity:0;  transform:rotate(var(--rot)) translateX(var(--travel)) scaleX(1)}
}
