/* ─────────────────────────────────────────────────────────────────────────
   Bishop Systems seasonal kit: HALLOWEEN
   Drop-in for any client site, any stack. Pairs with halloween.js.

   HOW TO USE
     1. Copy this file and halloween.js into the site (or paste the JS inline
        in <head>, it is four lines).
     2. Link this stylesheet LAST, after the site's own CSS.
     3. Nothing else. It self-activates on October 1 and self-expires on
        November 1, on the visitor's own clock, with no redeploy.

   WHAT IT DOES NOT DO, ON PURPOSE
     It does not touch the client's brand colour, their buttons, their links,
     or any text colour. A customer who learned that green means "book now" in
     September must not have to relearn it in October, and a body shop is not
     improved by its logo turning purple. This is an atmosphere layer over the
     site, not a repaint of it.

   TWO INTENSITIES, set on <html> by the script:
     data-season="halloween"              atmosphere only. Safe anywhere,
                                          light or dark, any brand colour.
     data-season="halloween" data-season-depth="full"
                                          adds the violet accent grade. Only
                                          for DARK sites with a warm accent.
                                          Check it on a real screen first.
   ───────────────────────────────────────────────────────────────────────── */

:root[data-season="halloween"] {
  /* The two seasonal colours. Override either on the client's own :root if
     their brand needs a different violet. */
  --hw-violet: #8B5CF6;
  --hw-ember: #F59E0B;

  /* How strong the atmosphere is. 1 is the tuned default. Drop to 0.5 on a
     light site if the fog reads as a smudge rather than as light. */
  --hw-intensity: 1;
}

/* ── The atmosphere ────────────────────────────────────────────────────────
   One fixed layer, painted behind everything. Violet bloom rising from the
   bottom corners, ember warmth from above, like a fire just out of frame.

   `position: fixed` and `pointer-events: none` together are what make this
   safe to drop onto a site nobody has read: it cannot shift a single element's
   layout, cannot trap a click, and cannot break a sticky header. It is one
   composited layer and it costs nothing to scroll. */
:root[data-season="halloween"] body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(120% 70% at 6% 106%,
      color-mix(in oklch, var(--hw-violet) calc(15% * var(--hw-intensity)), transparent),
      transparent 62%),
    radial-gradient(112% 62% at 97% 102%,
      color-mix(in oklch, var(--hw-violet) calc(11% * var(--hw-intensity)), transparent),
      transparent 58%),
    radial-gradient(92% 44% at 50% -10%,
      color-mix(in oklch, var(--hw-ember) calc(9% * var(--hw-intensity)), transparent),
      transparent 60%);
}

/* A light site needs the fog inverted in weight or it reads as dirt on the
   screen rather than light in the room. Detected by the site's own scheme
   rather than by asking the installer to pick. */
@media (prefers-color-scheme: light) {
  :root[data-season="halloween"]:not([data-season-depth="full"]) body::before {
    opacity: 0.55;
    mix-blend-mode: multiply;
  }
}

/* ── Depth: full ───────────────────────────────────────────────────────────
   Dark sites only. Cools and deepens the page ground so the client's warm
   accent reads as firelight against night. Still does not touch the accent
   itself. Only applies if the site uses a `--background` custom property,
   which most modern builds do; if it does not, this block is inert and the
   atmosphere above still works. */
:root[data-season="halloween"][data-season-depth="full"] {
  --background: oklch(0.128 0.012 300);
}

:root[data-season="halloween"][data-season-depth="full"] body::before {
  background:
    radial-gradient(124% 74% at 6% 106%,
      color-mix(in oklch, var(--hw-violet) calc(22% * var(--hw-intensity)), transparent),
      transparent 64%),
    radial-gradient(114% 66% at 97% 102%,
      color-mix(in oklch, var(--hw-violet) calc(17% * var(--hw-intensity)), transparent),
      transparent 60%),
    radial-gradient(94% 46% at 50% -10%,
      color-mix(in oklch, var(--hw-ember) calc(13% * var(--hw-intensity)), transparent),
      transparent 62%);
}

/* ── Optional ornament ─────────────────────────────────────────────────────
   Add class="hw-glow" to ONE element, usually the primary CTA or a seasonal
   offer badge, to give it a jack-o-lantern rim. Deliberately opt-in per
   element: an effect applied to every button is a costume, applied to one it
   is a highlight. */
:root[data-season="halloween"] .hw-glow {
  box-shadow:
    0 0 0 1px color-mix(in oklch, var(--hw-ember) 40%, transparent),
    0 0 28px -6px color-mix(in oklch, var(--hw-ember) 55%, transparent);
}

/* Motion is opt-in twice: the class, and the visitor not having asked for
   less of it. */
@media (prefers-reduced-motion: no-preference) {
  :root[data-season="halloween"] .hw-glow {
    animation: hw-flicker 4.5s ease-in-out infinite;
  }

  @keyframes hw-flicker {
    0%, 100% { box-shadow:
      0 0 0 1px color-mix(in oklch, var(--hw-ember) 40%, transparent),
      0 0 28px -6px color-mix(in oklch, var(--hw-ember) 55%, transparent); }
    48%      { box-shadow:
      0 0 0 1px color-mix(in oklch, var(--hw-ember) 52%, transparent),
      0 0 38px -4px color-mix(in oklch, var(--hw-ember) 68%, transparent); }
  }
}

/* Print gets none of it. A quoted estimate printed from the site should not
   arrive with a purple wash across it. */
@media print {
  :root[data-season="halloween"] body::before { display: none; }
  :root[data-season="halloween"] .hw-glow { box-shadow: none; animation: none; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   ORNAMENTS — opt-in, one element each
   ═══════════════════════════════════════════════════════════════════════════

   The atmosphere layer above is a `body::before` at z-index 0. That is right
   for a site whose sections are transparent over the body, and INVISIBLE on
   the more common case: a site built from opaque cards on an opaque page,
   where the fog paints and is immediately covered by the first section.

   Raising that layer above the content was tried on prscares.com and rejected
   — a full-viewport scrim dims the nav and the pricing cards, which is a worse
   page than no season at all. So anything that has to be SEEN is placed as a
   scoped ornament inside the one surface people actually look at.

   Each ornament is a real element rather than a pseudo-element, because a hero
   that already uses `::before`/`::after` for a scrim or a grain overlay is the
   norm, not the exception, and silently losing to one is a bad failure mode.

   INSTALL
     1. Put `class="hw-stage"` on the hero (gives it a positioning context and
        clips the ornaments to it). Skip it only if the hero is already
        `position: relative` AND `overflow: hidden`.
     2. Drop the ornament inside it, last, before the closing tag:
          <div class="hw-bats" aria-hidden="true"></div>
          <div class="hw-pumpkin" aria-hidden="true"></div>
     3. On a DARK hero add `hw-bats--night` for pale silhouettes.

   Outside the season every one of these is `display: none`, so the markup can
   sit in the page all year and costs one unmatched attribute selector. */

:root[data-season="halloween"] .hw-stage {
  position: relative;
  overflow: hidden;
}

.hw-bats,
.hw-pumpkin {
  display: none;
}

/* ── Bats ──────────────────────────────────────────────────────────────────
   Three, at three sizes, reading as distance rather than as a row of stickers.
   Dark by default: against a bright photo hero a pale bat disappears, and a
   silhouette is the honest read against a sky anyway. */
:root[data-season="halloween"] .hw-bats {
  display: block;
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: .55;
  background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 40'><path fill='%23141a24' d='M50 12c3 0 5 2 6 5 4-6 10-10 17-11-3 3-4 7-3 11 5-3 11-3 16 0-6 1-10 5-12 10-4-4-9-6-15-5-3 1-6 3-9 6-3-3-6-5-9-6-6-1-11 1-15 5-2-5-6-9-12-10 5-3 11-3 16 0-1-4 0-8-3-11 7 1 13 5 17 11 1-3 3-5 6-5z'/></svg>"), url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 40'><path fill='%23141a24' d='M50 12c3 0 5 2 6 5 4-6 10-10 17-11-3 3-4 7-3 11 5-3 11-3 16 0-6 1-10 5-12 10-4-4-9-6-15-5-3 1-6 3-9 6-3-3-6-5-9-6-6-1-11 1-15 5-2-5-6-9-12-10 5-3 11-3 16 0-1-4 0-8-3-11 7 1 13 5 17 11 1-3 3-5 6-5z'/></svg>"), url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 40'><path fill='%23141a24' d='M50 12c3 0 5 2 6 5 4-6 10-10 17-11-3 3-4 7-3 11 5-3 11-3 16 0-6 1-10 5-12 10-4-4-9-6-15-5-3 1-6 3-9 6-3-3-6-5-9-6-6-1-11 1-15 5-2-5-6-9-12-10 5-3 11-3 16 0-1-4 0-8-3-11 7 1 13 5 17 11 1-3 3-5 6-5z'/></svg>");
  background-repeat: no-repeat;
  background-size: 84px auto, 52px auto, 34px auto;
  background-position: 11% 18%, 76% 12%, 47% 30%;
}

/* Night hero: flip to pale, or the silhouettes vanish into the dark. */
:root[data-season="halloween"] .hw-bats--night {
  opacity: .34;
  background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 40'><path fill='%23cfe0f2' d='M50 12c3 0 5 2 6 5 4-6 10-10 17-11-3 3-4 7-3 11 5-3 11-3 16 0-6 1-10 5-12 10-4-4-9-6-15-5-3 1-6 3-9 6-3-3-6-5-9-6-6-1-11 1-15 5-2-5-6-9-12-10 5-3 11-3 16 0-1-4 0-8-3-11 7 1 13 5 17 11 1-3 3-5 6-5z'/></svg>"), url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 40'><path fill='%23cfe0f2' d='M50 12c3 0 5 2 6 5 4-6 10-10 17-11-3 3-4 7-3 11 5-3 11-3 16 0-6 1-10 5-12 10-4-4-9-6-15-5-3 1-6 3-9 6-3-3-6-5-9-6-6-1-11 1-15 5-2-5-6-9-12-10 5-3 11-3 16 0-1-4 0-8-3-11 7 1 13 5 17 11 1-3 3-5 6-5z'/></svg>"), url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 40'><path fill='%23cfe0f2' d='M50 12c3 0 5 2 6 5 4-6 10-10 17-11-3 3-4 7-3 11 5-3 11-3 16 0-6 1-10 5-12 10-4-4-9-6-15-5-3 1-6 3-9 6-3-3-6-5-9-6-6-1-11 1-15 5-2-5-6-9-12-10 5-3 11-3 16 0-1-4 0-8-3-11 7 1 13 5 17 11 1-3 3-5 6-5z'/></svg>");
}

/* ── Jack-o-lantern ────────────────────────────────────────────────────────
   Bottom corner, sized in vw so it stays proportionate without a media query,
   and clamped so it is neither a speck on a phone nor a mascot on a monitor. */
:root[data-season="halloween"] .hw-pumpkin {
  display: block;
  position: absolute;
  left: clamp(12px, 3vw, 44px);
  bottom: clamp(10px, 2.4vw, 34px);
  z-index: 1;
  width: clamp(46px, 6vw, 88px);
  aspect-ratio: 1;
  pointer-events: none;
  background: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><path fill='%234a7c2f' d='M47 20c0-7 4-12 11-14l3 6c-4 1-7 4-7 9z'/><path fill='none' stroke='%234a7c2f' stroke-width='3' stroke-linecap='round' d='M61 12c6-3 11-1 12 3s-3 7-7 5'/><ellipse cx='28' cy='62' rx='22' ry='33' fill='%23d46a17'/><ellipse cx='72' cy='62' rx='22' ry='33' fill='%23d46a17'/><ellipse cx='39' cy='62' rx='21' ry='35' fill='%23ea7f1e'/><ellipse cx='61' cy='62' rx='21' ry='35' fill='%23ea7f1e'/><ellipse cx='50' cy='62' rx='23' ry='36' fill='%23f7941d'/><circle cx='40' cy='54' r='6' fill='%235c2708'/><circle cx='60' cy='54' r='6' fill='%235c2708'/><path fill='%235c2708' d='M34 70c5 8 11 12 16 12s11-4 16-12c-4 2-7 3-9 3l-1-5-3 5h-6l-3-5-1 5c-2 0-5-1-9-3z'/></svg>") no-repeat center / contain;
  filter: drop-shadow(0 0 18px color-mix(in oklch, var(--hw-ember) 45%, transparent));
}

:root[data-season="halloween"] .hw-pumpkin--right {
  left: auto;
  right: clamp(12px, 3vw, 44px);
}

/* ── Motion ────────────────────────────────────────────────────────────────
   Transform and filter only, so both stay on the compositor. Opt-in twice:
   the ornament has to be present, and the visitor must not have asked for
   less motion. */
@media (prefers-reduced-motion: no-preference) {
  :root[data-season="halloween"] .hw-bats {
    animation: hw-drift 24s ease-in-out infinite alternate;
  }

  :root[data-season="halloween"] .hw-pumpkin {
    animation: hw-candle 5.5s ease-in-out infinite;
  }

  @keyframes hw-drift {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(2.6%, -1.8%, 0); }
  }

  /* A candle gutters, it does not pulse on a metronome — hence the uneven
     stops rather than a symmetric ease. */
  @keyframes hw-candle {
    0%, 100% { filter: drop-shadow(0 0 18px color-mix(in oklch, var(--hw-ember) 45%, transparent)); }
    41%      { filter: drop-shadow(0 0 27px color-mix(in oklch, var(--hw-ember) 66%, transparent)); }
    63%      { filter: drop-shadow(0 0 15px color-mix(in oklch, var(--hw-ember) 38%, transparent)); }
  }
}

/* A printed estimate or invoice gets none of it. */
@media print {
  :root[data-season="halloween"] .hw-bats,
  :root[data-season="halloween"] .hw-pumpkin { display: none; }
}
