/* -----------------------------------------------------------------------------
 * Project:       Kirby Castle
 * Owner:         Joshua H. Kirby
 * Copyright:     Copyright (c) 2026 Joshua H. Kirby. All rights reserved.
 * Last Modified: 2026-07-18
 * --------------------------------------------------------------------------- */

/* Shared castle-art page background -- the full-viewport backdrop (drifting
 * shadow band, castle art + vignette with a slow brightness breathe, and a
 * twinkling star field), extracted out of pages/outside.css (where it
 * originally lived, back when outside.html was the only page using it) so
 * register.html can reuse the exact same effect rather than duplicating it.
 * A page using this expects a `.castle-page` wrapper as the outermost
 * element inside <body>, with a `.star-field` (holding six `.star-1`..
 * `.star-6` spans, see the markup in outside.html/register.html) as its
 * first child and the page's real content -- given position: relative and
 * a z-index of 3 or higher by that page's own CSS -- after it, so the
 * content paints above both the background image (z-index 1) and the
 * shadow band/star field (z-index 2). */

.castle-page {
  position: relative;
  min-height: 100vh;
  padding: 2rem;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;

  background-color: var(--bg-page);
}

/*
 * A slow shadow band drifting across the art, mimicking clouds passing over
 * the sun. Sits above the image (z-index 2, vs. 1 on ::after below) but
 * under all real UI content, which is why each page's own top-level content
 * element needs at least z-index 3. ease-in-out + alternate avoids a
 * jump-cut at the loop boundary — it drifts one way, then drifts back.
 */
.castle-page::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: linear-gradient(
    120deg,
    rgba(0, 0, 0, 0.32),
    transparent 40%,
    transparent 60%,
    rgba(0, 0, 0, 0.32)
  );
  background-size: 250% 250%;
  animation: sky-drift 46s ease-in-out infinite alternate;
  pointer-events: none;
}

@keyframes sky-drift {
  from {
    background-position: 0% 0%;
  }

  to {
    background-position: 100% 100%;
  }
}

/*
 * Single image layer at `cover`, so it always fills the viewport edge to
 * edge with no gaps regardless of aspect ratio. No separate blurred fill
 * layer — that approach left a visible seam wherever the sharp and
 * blurred content met, since a hard sharp/blur detail boundary shows even
 * when colors are matched. Cropping here is the accepted tradeoff.
 * The vignette gradients ride along as extra background-image layers on
 * top of the same element.
 */
.castle-page::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background-image:
    linear-gradient(to bottom, rgba(0, 0, 0, 0.35), transparent 35%),
    radial-gradient(circle at center, transparent 25%, rgba(0, 0, 0, 0.28) 100%),
    url("../images/castle.png");
  background-size: auto, auto, cover;
  background-position: center, center, center top;
  background-repeat: no-repeat, no-repeat, no-repeat;
  pointer-events: none;

  /*
   * Gentle brightness breathe, on a period independent from sky-drift above
   * (38s vs. 46s) so the two never lock into a repeating combined pattern.
   */
  animation: castle-breathe 38s ease-in-out infinite alternate;
}

@keyframes castle-breathe {
  from {
    filter: brightness(1);
  }

  to {
    filter: brightness(0.9);
  }
}

/* ── STAR FIELD ──────────────────────────────────────────── */

.star-field {
  position: absolute;
  inset: 0;
  z-index: 2;
  overflow: hidden;
  pointer-events: none;
}

.star {
  position: absolute;
  width: 3px;
  height: 3px;
  border-radius: 50%;

  background: #fff;
  box-shadow: 0 0 6px 1px rgba(255, 255, 255, 0.9);

  opacity: 0;
  animation: star-twinkle 8s ease-in-out infinite;
}

/*
 * Mostly invisible (0%-70%), a brief double-flicker, back to invisible —
 * "periodic" rather than a constant pulse. Each star below overrides
 * duration/delay so six copies of this never twinkle in unison.
 */
@keyframes star-twinkle {
  0%,
  70% {
    opacity: 0;
    transform: scale(0.5);
  }

  78% {
    opacity: 1;
    transform: scale(1);
  }

  86% {
    opacity: 0.4;
    transform: scale(0.8);
  }

  94% {
    opacity: 1;
    transform: scale(1);
  }

  100% {
    opacity: 0;
    transform: scale(0.5);
  }
}

/*
 * Spread wider across the top and down where the art actually has a gap:
 * two sit low, over the clear sky beside the beacon spire and above the
 * tallest castle spire (before the cloud bank thickens); the rest stay in
 * the thin clear strip above the banner. Anywhere else at this height is
 * cloud, mountain, or the tree at far right.
 */
.star-1 {
  top: 0.4%;
  left: 33%;
  animation-duration: 7s;
  animation-delay: 0s;
}

.star-2 {
  top: 0.8%;
  left: 50%;
  animation-duration: 9s;
  animation-delay: 2.4s;
}

.star-3 {
  top: 14%;
  left: 36%;
  animation-duration: 8s;
  animation-delay: 1.1s;
}

.star-4 {
  top: 13%;
  left: 65%;
  animation-duration: 10s;
  animation-delay: 4.2s;
}

.star-5 {
  top: 0.5%;
  left: 82%;
  animation-duration: 7.5s;
  animation-delay: 3s;
}

.star-6 {
  top: 0.9%;
  left: 91%;
  animation-duration: 8.5s;
  animation-delay: 5.5s;
}

/* Ambient motion above is decorative only — respect reduced-motion. */
@media (prefers-reduced-motion: reduce) {
  .castle-page::before,
  .castle-page::after {
    animation: none;
  }

  .star {
    animation: none;
    opacity: 0.5;
  }
}
