/* The living meadow layer — grass strips that gust in the wind, and a sky
   lane for rare ambient flybys (plane, birds, meteor, fireflies). Rendered by
   shared/_meadow and directed by the meadow Stimulus controller.

   Performance contract: every animation here is transform/opacity only
   (GPU compositor — no layout, no paint), sprites exist only while their
   event plays, and between events nothing animates at all. */
@layer components {
  .meadow {
    position: fixed;
    inset: 0;
    /* Behind all content, above the body's backdrop image. */
    z-index: -1;
    overflow: hidden;
    pointer-events: none;
  }

  /* ── Grass ──────────────────────────────────────────────────────────
     Three depth strips over the backdrop's ground band. The wrapper is sized
     to max(100vw, 160vh): exactly the painted width of the 1600×1000 backdrop
     under `background-size: cover; background-position: center bottom`, so
     blades keep their place in the scene at every aspect ratio. */
  .meadow__grass {
    position: absolute;
    bottom: 0;
    left: 50%;
    width: max(100vw, 160vh);
    aspect-ratio: 1600 / 260;
    transform: translateX(-50%);
  }

  .meadow__blades {
    position: absolute;
    inset: 0;
    background-size: 100% 100%;
    background-repeat: no-repeat;
    /* Blades bend from their roots. */
    transform-origin: 50% 100%;
  }

  /* --amp scales the gust per depth: near grass bends most, far barely. */
  .meadow__blades--far  { background-image: var(--grass-far);  --amp: 0.35; }
  .meadow__blades--mid  { background-image: var(--grass-mid);  --amp: 0.65; }
  .meadow__blades--near { background-image: var(--grass-near); --amp: 1; }

  /* A gust: bend with the wind, overshoot back, settle. The controller sets
     --gust (signed strength) and --gust-dur, then removes the class on
     animationend so nothing animates between gusts. Depth layers lag a beat
     so the gust reads as travelling through the meadow. */
  .meadow__grass.is-gusting .meadow__blades {
    animation: meadow-gust var(--gust-dur, 5.5s) ease-in-out both;
  }
  .meadow__grass.is-gusting .meadow__blades--mid  { animation-delay: 0.14s; }
  .meadow__grass.is-gusting .meadow__blades--near { animation-delay: 0.3s; }

  @keyframes meadow-gust {
    0%   { transform: skewX(0deg); }
    35%  { transform: skewX(calc(var(--gust, 3deg) * var(--amp))); }
    58%  { transform: skewX(calc(var(--gust, 3deg) * var(--amp) * -0.3)); }
    78%  { transform: skewX(calc(var(--gust, 3deg) * var(--amp) * 0.12)); }
    100% { transform: skewX(0deg); }
  }

  /* ── Sky lane ─────────────────────────────────────────────────────── */
  .meadow__sky {
    position: absolute;
    inset: 0;
  }

  .sky-sprite {
    position: absolute;
    top: var(--fly-y, 16%);
    left: 0;
  }

  /* Horizontal crossing — the controller sets start/end (either direction),
     altitude and duration as inline custom properties. */
  .sky-sprite--cross {
    animation: sky-cross var(--fly-dur, 50s) linear both;
  }
  .sky-sprite--flip svg { transform: scaleX(-1); }

  @keyframes sky-cross {
    from { transform: translateX(var(--fly-from, -14rem)); }
    to   { transform: translateX(var(--fly-to, 100vw)); }
  }

  /* Aircraft beacons (night): red anti-collision pulse and a white strobe's
     quick double-flash, offset like the real thing. */
  .sky-sprite .beacon--red   { animation: beacon-red 1.6s infinite; }
  .sky-sprite .beacon--white { animation: beacon-white 1.6s infinite 0.5s; }

  @keyframes beacon-red {
    0%, 12%       { opacity: 1; }
    16%, 100%     { opacity: 0; }
  }
  @keyframes beacon-white {
    0%, 4%        { opacity: 1; }
    5%, 9%        { opacity: 0; }
    10%, 14%      { opacity: 1; }
    15%, 100%     { opacity: 0; }
  }

  /* Bird flock: the crossing is on the sprite; the flock bobs gently and each
     bird flaps (scaleY about its own centre) with a per-bird delay. */
  .sky-sprite__bob { animation: flock-bob 5s ease-in-out infinite alternate; }
  .sky-sprite .bird {
    transform-box: fill-box;
    transform-origin: center;
    animation: bird-flap 0.5s ease-in-out infinite alternate;
  }

  @keyframes flock-bob {
    from { transform: translateY(0); }
    to   { transform: translateY(9px); }
  }
  @keyframes bird-flap {
    from { transform: scaleY(1); }
    to   { transform: scaleY(0.45); }
  }

  /* Shooting star: a gradient streak, head leading, one-and-a-half seconds. */
  .sky-sprite--meteor {
    width: 110px;
    height: 2px;
    border-radius: 1px;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.95));
    animation: meteor 1.5s ease-out both;
  }

  @keyframes meteor {
    0%   { transform: rotate(33deg) translateX(0);      opacity: 0; }
    12%  { opacity: 1; }
    100% { transform: rotate(33deg) translateX(58vmin); opacity: 0; }
  }

  /* Fireflies: each fly drifts along its own --dx/--dy while the inner dot
     pulses. The whole troupe fades in and out over the event's lifetime. */
  .sky-sprite--flies { top: auto; bottom: 9vh; }

  .firefly {
    position: absolute;
    animation: fly-drift var(--fly-life, 16s) ease-in-out both;
  }
  .firefly::after {
    content: '';
    display: block;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: radial-gradient(circle,
      rgba(232, 255, 176, 0.95),
      rgba(205, 242, 122, 0.4) 50%,
      transparent 72%);
    animation: fly-pulse 2.4s ease-in-out infinite;
    animation-delay: inherit;
  }

  @keyframes fly-drift {
    0%       { transform: translate(0, 0); opacity: 0; }
    12%, 86% { opacity: 1; }
    100%     { transform: translate(var(--dx, 70px), var(--dy, -40px)); opacity: 0; }
  }
  @keyframes fly-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.2; }
  }

  /* Stillness wins: no wind, no flybys. The controller also checks this and
     never schedules anything — this rule is the belt to that suspenders. */
  @media (prefers-reduced-motion: reduce) {
    .meadow * { animation: none !important; }
  }
}
