/* Halloween, 1 October - 1 November.

   Decorations only: nothing here changes a colour, a font or a layout the site
   already has. season.js places the pieces; this file says how they look.
   None of them takes a click except the two easter eggs (the dangling spider and
   the pumpkins in the About section), and all of them stand still under
   prefers-reduced-motion. */

/* The spinner becomes a web, turning a little slower than the aperture. */
:root {
  --df-spinner-mask: url("/static/seasons/halloween/web-spinner.svg");
  --df-spinner-speed: 2.4s;
}

/* ---------- Section dividers: a sagging silk thread with its spider ---------- */
/* The rules between sections are top borders, either on a container's inner
   block, on a container itself, or on the partner strip. The thread is a
   repeated swag centred on the block, so a low point always falls in the
   middle, which is where the spider hangs. */
.container > .border-top,
.container.border-top,
.partner-strip {
  border-top-color: transparent !important;
  background-image: url("spider.svg"), url("thread.svg");
  background-repeat: no-repeat, repeat-x;
  background-position: center 9px, center top;
  background-size: 16px 16px, 160px 20px;
}

/* ---------- Webs in the corners ---------- */
.df-web {
  position: absolute;
  z-index: 1;
  pointer-events: none;
  background-color: rgba(48, 44, 56, 0.2);
  -webkit-mask: url("web-corner.svg") center / contain no-repeat;
  mask: url("web-corner.svg") center / contain no-repeat;
}
.df-web--light { background-color: rgba(255, 255, 255, 0.5); }
.df-web--tl { top: 0; left: 0; }
.df-web--tr { top: 0; right: 0; transform: scaleX(-1); }
.df-web--bl { bottom: 0; left: 0; transform: scaleY(-1); }
.df-web--br { bottom: 0; right: 0; transform: scale(-1, -1); }
/* Above the banner's darkening scrim (z-index 1), still under its title. */
.hero-portfolio > .df-web { z-index: 2; }

/* ---------- The spider under the logo ---------- */
/* It lets itself down once when the page opens, then drifts slowly up and down
   on its thread by itself -- no reaction to the mouse, which made it jump. Once
   the page is scrolled it is wound back up into the logo, out of the way. */
.df-dangler {
  position: absolute;
  top: 100%;
  left: 50%;
  width: 1px;
  z-index: 2;
  pointer-events: none;
  /* Room below the thread's end for the spider hanging off it. */
  clip-path: inset(0 -20px -30px -20px);
  transition: clip-path 0.9s ease-in-out, opacity 0.9s ease-in-out;
}
.df-dangler-thread {
  display: block;
  width: 1px;
  height: 52px;
  /* Mid grey reads on both the white header and a photo. */
  background: rgba(130, 122, 136, 0.7);
  animation:
    df-drop 2.4s cubic-bezier(0.25, 0.1, 0.25, 1) both,
    df-bob 7s ease-in-out 2.4s infinite alternate;
}
.df-dangler-spider {
  position: absolute;
  left: -11px;
  bottom: -18px;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  -webkit-appearance: none;
  appearance: none;
  background: url("spider.svg") center / contain no-repeat;
  filter: drop-shadow(0 0 1px rgba(255, 255, 255, 0.6));
  pointer-events: auto;
  cursor: pointer;
  transform-origin: 50% -20px;
  animation: df-sway 6s ease-in-out infinite;
}
#header.df-topbar-folded .df-dangler { clip-path: inset(0 -20px 100% -20px); opacity: 0; }
#header.df-topbar-folded .df-dangler-spider { pointer-events: none; }

@keyframes df-drop { from { height: 0; } to { height: 52px; } }
@keyframes df-bob { from { height: 52px; } to { height: 84px; } }
@keyframes df-sway {
  0%, 100% { transform: rotate(-4deg); }
  50% { transform: rotate(4deg); }
}

/* ---------- Ghosts hiding behind things ---------- */
/* The ghost sits behind its host's top edge and rises out of it on hover, or
   for a moment when it first scrolls into view (season.js adds .df-peek). */
.df-ghost {
  position: absolute;
  top: 0;
  width: 40px;
  height: 46px;
  pointer-events: none;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
  transition: transform 0.7s cubic-bezier(0.34, 1.35, 0.64, 1);
}
.df-ghost svg { display: block; width: 100%; height: 100%; }
/* Behind a package card: the card is lifted above it. One ghost per card, and
   season.js brings one of them out at a time. */
.df-ghost-host > .card { z-index: 1; }
.df-ghost-host > .df-ghost { right: var(--df-ghost-at, 18%); z-index: 0; }
.df-ghost.df-peek svg { animation: df-ghost-float 1.6s ease-in-out infinite alternate; }
@keyframes df-ghost-float { from { transform: rotate(-5deg); } to { transform: rotate(5deg); } }
.df-ghost-host:hover > .df-ghost,
.df-ghost-host > .df-ghost.df-peek { transform: translateY(-80%); }
/* Behind the footer: under it in the stacking order, so the dark band hides it. */
footer > .df-ghost { left: 12%; z-index: -1; }
footer:hover > .df-ghost,
footer > .df-ghost.df-peek { transform: translateY(-70%); }

/* ---------- The bat hanging under the main image ---------- */
/* The perch takes no room: the page below does not move by a pixel. */
.df-perch { position: relative; height: 0; z-index: 3; pointer-events: none; }
.df-roost {
  position: absolute;
  top: -3px;
  right: 22%;
  width: 40px;
  height: 60px;
  transform-origin: 50% 0;
  animation: df-roost-sway 5s ease-in-out infinite;
  transition: opacity 0.25s, transform 0.25s;
}
.df-roost svg { display: block; width: 100%; height: 100%; }
.df-roost-eyes { animation: df-roost-blink 7s infinite; transform-origin: 50% 59.5px; transform-box: view-box; }
.df-roost.df-roost-gone { opacity: 0; transform: scale(0.6) translateY(-10px); animation: none; }
@keyframes df-roost-sway {
  0%, 100% { transform: rotate(-4deg); }
  50% { transform: rotate(4deg); }
}
@keyframes df-roost-blink {
  0%, 60%, 64%, 100% { transform: scaleY(1); }
  62% { transform: scaleY(0.1); }
}
@media (max-width: 575.98px) {
  .df-roost { right: 14%; width: 32px; height: 48px; }
}

/* ---------- Pumpkins sitting on the About section's bottom edge ---------- */
.df-pumpkin {
  position: absolute;
  bottom: -2px;
  z-index: 1;
  padding: 0;
  border: 0;
  -webkit-appearance: none;
  appearance: none;
  background: url("pumpkin.svg") center bottom / contain no-repeat;
  cursor: pointer;
  filter: drop-shadow(0 3px 3px rgba(0, 0, 0, 0.15));
}
.df-pumpkin--big { left: 4%; width: 46px; height: 43px; }
.df-pumpkin--small { left: calc(4% + 40px); width: 30px; height: 28px; }

/* ---------- Eyes in the dark footer ---------- */
.df-eyes {
  position: absolute;
  right: 1.25rem;
  bottom: 0.9rem;
  display: flex;
  gap: 8px;
  pointer-events: none;
}
.df-eyes i {
  width: 8px;
  height: 5px;
  border-radius: 50% 50% 50% 50% / 100% 100% 0 0;
  background: #ffcf70;
  box-shadow: 0 0 8px #ffcf70;
  animation: df-blink 6s infinite;
}
.df-eyes i:first-child { --r: 10deg; transform: rotate(10deg); }
.df-eyes i:last-child { --r: -10deg; transform: rotate(-10deg); }
@keyframes df-blink {
  0%, 46%, 50%, 100% { transform: rotate(var(--r)) scaleY(1); }
  48% { transform: rotate(var(--r)) scaleY(0.1); }
}

/* ---------- The chase along the bottom of the footer ---------- */
.df-chase {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 6px;
  height: 44px;
  overflow: hidden;
  pointer-events: none;
}
.df-chaser { position: absolute; left: 0; bottom: 0; }
.df-chaser-body { display: block; }
.df-chaser-body.df-flip { transform: scaleX(-1); }
.df-chaser svg { display: block; width: auto; }
.df-chaser--skeleton svg { height: 42px; }
.df-chaser--ghost svg { height: 34px; animation: df-ghost-run 0.45s ease-in-out infinite alternate; }
/* The skeleton's legs and arms: two poses swapped on every stride. */
.df-chaser--skeleton .pose-a { animation: df-stride 0.36s steps(1) infinite; }
.df-chaser--skeleton .pose-b { animation: df-stride 0.36s steps(1) infinite reverse; }
@keyframes df-stride { 0% { opacity: 1; } 50% { opacity: 0; } }
@keyframes df-ghost-run { from { transform: translateY(0) rotate(-6deg); } to { transform: translateY(-5px) rotate(4deg); } }

/* ---------- Bats and running spiders, over the whole window ---------- */
/* Under the message toasts (1050) and dialogs, over everything else. */
.df-sky {
  position: fixed;
  inset: 0;
  z-index: 1040;
  overflow: hidden;
  pointer-events: none;
}
.df-bat { position: absolute; top: 0; left: 0; color: #1c1622; }
.df-bat svg { display: block; width: 100%; height: auto; transform-origin: 50% 45%; animation: df-flap 0.24s ease-in-out infinite alternate; }
@keyframes df-flap { to { transform: scaleY(0.6); } }
.df-witch { position: absolute; top: 0; left: 0; color: #1c1622; }
.df-witch-body { position: relative; display: block; animation: df-broom 2.2s ease-in-out infinite alternate; }
.df-witch-body.df-flip { transform: scaleX(-1); animation-name: df-broom-flip; }
.df-witch svg { display: block; width: 100%; height: auto; }
@keyframes df-broom { from { transform: rotate(-3deg); } to { transform: rotate(3deg); } }
@keyframes df-broom-flip { from { transform: scaleX(-1) rotate(-3deg); } to { transform: scaleX(-1) rotate(3deg); } }
/* Sparks off the bristles: they twinkle in place at the back of the broom. */
.df-spark {
  position: absolute;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: #ffcf70;
  box-shadow: 0 0 6px #ffcf70;
  animation: df-spark 0.9s ease-in-out infinite;
}
.df-spark:nth-of-type(1) { left: -2%; top: 62%; }
.df-spark:nth-of-type(2) { left: -7%; top: 74%; animation-delay: 0.3s; }
.df-spark:nth-of-type(3) { left: 1%; top: 86%; animation-delay: 0.6s; }
@keyframes df-spark {
  0%, 100% { opacity: 0; transform: scale(0.4); }
  50% { opacity: 1; transform: scale(1); }
}
.df-runner { position: absolute; top: 0; left: 0; width: 22px; height: 22px; background: url("spider.svg") center / contain no-repeat; }

@media (prefers-reduced-motion: reduce) {
  .df-dangler, .df-dangler-thread, .df-dangler-spider, .df-eyes i, .df-ghost, .df-ghost svg,
  .df-roost, .df-roost-eyes { animation: none; transition: none; }
}

@media print {
  .df-web, .df-dangler, .df-ghost, .df-pumpkin, .df-eyes, .df-sky, .df-perch, .df-chase { display: none !important; }
}
