/* batman.css -- loaded only by /batman. Split out of fanpages.css. */

/* ═════════════ the descent: Gotham above, the Batcave below ═════════════

   --depth is the whole mechanism: 0 at the top of the page (the city) and 1
   once you have scrolled into the cave, set by batman-descent.js. Declared
   here as well as there, so with no scripts the page is Gotham at night the
   way it always was, and @property gives it a type, which is what lets a
   browser interpolate it instead of snapping between the two ends.

   Everything below reads it. The city's layers go up and fade, the cave's
   come in, and because both sets sit in the same fixed backdrop the two
   never meet at an edge. */
@property --depth {
  syntax: "<number>"; inherits: true; initial-value: 0;
}

.bat-sky {
  --depth: 0;
  position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden;
  /* the city's night sky, crossfaded to the cave's cold underground dark */
  background:
    radial-gradient(90% 70% at 50% 100%, #10131a 0%, #0a0c11 50%, #030405 100%);
}

.bat-sky > * { position: absolute; inset: 0; display: block; }

/* Gotham is meant to be unlit. Everything here stays low on purpose. */

/* The city rises away as you go under it: it lifts off the bottom of the
   screen and dims, so by the time the cave is in, the skyline is gone. */
.bat-city {
  inset: auto 0 0 0; height: 54%;
  transform: translateY(calc(var(--depth) * -42%));
  opacity: calc(1 - var(--depth) * 1.35);
}

.bat-city svg { position: absolute; inset: 0; width: 100%; height: 100%; }

.bc-far  { fill: #0c0f16; }

.bc-near { fill: #06080d; }

.bc-lit  { fill: #6a5a2a; opacity: .55; }

/* the signal, thrown on the cloud base */
/* The signal is thrown on the cloud, so it belongs to the city: underground
   there is no cloud to throw it on. It goes up and out with the skyline. */
.bat-signal {
  inset: 4% auto auto 50%; translate: -50% 0;
  width: clamp(200px, 28vw, 420px); aspect-ratio: 1; opacity: .12;
}

.bat-signal svg { width: 100%; height: 100%; display: block; }

.bsg-beam { fill: #e8d9a4; }

.bat-signal {
  filter: blur(1px);
  animation: bat-flicker 9s ease-in-out infinite alternate;
  /* bat-flicker owns the opacity (it is the flicker), so the depth fade
     cannot use it too. It rides on the beam's fill-opacity instead, and the
     whole signal lifts away with the skyline. */
  transform: translateY(calc(var(--depth) * -30vh));
}

.bsg-beam { fill-opacity: calc(1 - var(--depth) * 1.6); }

/* rain, two sheets */
.bat-rain {
  inset: -20% -20% 0 -20%;
  background-image:
    repeating-linear-gradient(78deg, rgba(170,190,215,.07) 0 1px, transparent 1px 11px),
    repeating-linear-gradient(76deg, rgba(150,175,205,.05) 0 1px, transparent 1px 17px);
  mask-image: linear-gradient(180deg, transparent 0, #000 20%, #000 78%, transparent 98%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 20%, #000 78%, transparent 98%);
  animation: bat-fall 1.1s linear infinite;
  /* rain is weather, and there is none underground */
  opacity: calc(1 - var(--depth) * 1.5);
}

/* fill only, no stroke: the two mirrored halves meet down the centerline and a
   stroke would draw a seam straight through the middle of the blade */
.btr-body  { fill: #262b33; }

.btr-bevel { fill: #39414b; }

.btr-edge  { fill: none; stroke: #cdd8e4; stroke-width: 3; stroke-linejoin: round; stroke-linecap: round; }

.btr {
  transform-box: view-box; transform-origin: 200px 84px;
  animation: bat-spin 7s cubic-bezier(.45,0,.55,1) infinite;
  filter: drop-shadow(0 8px 18px rgba(0,0,0,.7));
}

.bat-sky::before {                     /* the searchlight cone */
  content: ""; position: absolute; left: 50%; bottom: -10%; translate: -50% 0;
  width: 120vw; height: 120vh;
  background: conic-gradient(from 200deg at 50% 100%, transparent 0 24deg, rgba(200,215,235,.055) 30deg, transparent 36deg);
  filter: blur(6px);
  opacity: calc(1 - var(--depth) * 1.5);
}

.bat-sky::after {                      /* the disc it throws */
  content: ""; position: absolute; left: 50%; top: 10%; translate: -50% 0;
  width: clamp(180px, 26vw, 380px); aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle, rgba(210,225,245,.09), transparent 68%);
  opacity: calc(1 - var(--depth) * 1.6);
}

/* ═════════════ the cave ═════════════
   Over the city, in as --depth goes up. The lighting is the Batcave's own:
   cold blue off the wall of monitors, which on this page is above the top of
   the screen and out of frame, and one warm sodium spill off to the left.
   Same palette as /batcomputer/, which is the room this is the inside of. */
/* The cave's own layers are grandchildren of .bat-sky, so the
   `.bat-sky > *` rule above does not reach them: without this they are
   inline, static and 0x0, which is to say invisible, which is exactly how
   they first shipped. */
.bat-cave > * { position: absolute; display: block; }

/* Everything in here is pitched HIGH on purpose. The whole backdrop is held
   at .36 by the site-wide brightness guard (fanpages.css, [class$="-sky"]),
   which is a ceiling worth keeping -- it is what stops a backdrop drowning
   the text. But it means a layer drawn at the value that looks right on its
   own arrives at about a third of it, and the first cut of this cave was
   invisible on the page for exactly that reason. These are the values AFTER
   the cap, not before it. */
.bat-cave {
  opacity: var(--depth);
  background:
    /* cold light down from the wall of monitors, off the top of the screen */
    radial-gradient(75% 50% at 50% -10%, rgba(140,195,235,.42), transparent 74%),
    /* one warm sodium lamp, low and to the left */
    radial-gradient(38% 34% at 6% 104%, rgba(245,197,66,.16), transparent 72%),
    /* and the dark the cave actually is, closing in on all four corners */
    radial-gradient(115% 90% at 50% 40%, transparent 36%, rgba(0,0,0,.96));
}

/* The rock walls. Down both sides and clipped to a ragged inner edge, so the
   middle of the screen (where the page's text is) stays clear and the cave
   closes in around it rather than over it. They slide in from off-screen as
   you descend. */
.bcv-wall {
  inset: 0 auto 0 auto; width: 30vw; max-width: 420px;
  background:
    /* the strata, and the damp catching the monitor light along them */
    repeating-linear-gradient(104deg, rgba(0,0,0,.55) 0 3px, transparent 3px 15px),
    repeating-linear-gradient(72deg, rgba(150,200,235,.07) 0 2px, transparent 2px 21px),
    linear-gradient(92deg, #161d27 0%, #0d131c 54%, #04060a 100%);
}

.bcv-wall--l {
  left: 0;
  transform: translateX(calc((1 - var(--depth)) * -100%));
  clip-path: polygon(0 0, 100% 0, 62% 9%, 88% 19%, 58% 29%, 92% 38%, 64% 48%, 86% 58%, 54% 67%, 90% 77%, 60% 86%, 84% 94%, 56% 100%, 0 100%);
}

.bcv-wall--r {
  right: 0;
  transform: translateX(calc((1 - var(--depth)) * 100%));
  clip-path: polygon(100% 0, 0 0, 40% 10%, 12% 20%, 44% 30%, 8% 39%, 38% 49%, 14% 59%, 46% 68%, 10% 78%, 40% 87%, 16% 95%, 44% 100%, 100% 100%);
}

/* the stalactite ceiling, coming down from the top of the screen */
.bcv-roof {
  inset: 0 0 auto 0; height: clamp(120px, 19vh, 240px);
  transform: translateY(calc((1 - var(--depth)) * -100%));
}

.bcv-roof svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

/* Lit from below by the monitors, the way the walls are: the teeth read as
   rock catching light, not as a black bar across the top of the screen. */
.bcv-roof path { fill: url(#bcvRock); }

/* The pool at the foot of the cave: still water, the monitors' light on it.
   It comes up rather than fading in, the way the ceiling comes down. */
.bcv-pool {
  inset: auto 0 0 0; height: 16%;
  transform: translateY(calc((1 - var(--depth)) * 100%));
  background:
    repeating-linear-gradient(0deg, rgba(150,200,235,.13) 0 1px, transparent 1px 7px),
    linear-gradient(180deg, rgba(110,170,210,.30), rgba(6,10,16,.92) 72%);
  mask-image: linear-gradient(180deg, transparent 0, #000 36%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 36%);
}

/* Two drip lines, falling at different rates off different teeth. The
   gradient is one short bright streak in a transparent column; the column is
   repeated across the screen and the animation falls it. */
.bcv-drip {
  background-image:
    repeating-linear-gradient(90deg, transparent 0 17vw, rgba(190,222,245,.70) 17vw calc(17vw + 1px), transparent calc(17vw + 1px) 34vw),
    repeating-linear-gradient(90deg, transparent 0 29vw, rgba(190,222,245,.48) 29vw calc(29vw + 1px), transparent calc(29vw + 1px) 58vw);
  background-size: 100% 13vh, 100% 21vh;
  background-repeat: repeat-x;
  mask-image: linear-gradient(180deg, #000 0, transparent 82%);
  -webkit-mask-image: linear-gradient(180deg, #000 0, transparent 82%);
  animation: bcv-drip 2.6s linear infinite, bcv-drip2 4.1s linear infinite;
}

@keyframes bcv-drip  { from { background-position-y: -13vh, 0; } to { background-position-y: 100vh, 0; } }

@keyframes bcv-drip2 { from { background-position-y: 0, -21vh; } to { background-position-y: 0, 100vh; } }

/* The backdrop is decoration: with reduced motion on, it still goes from the
   city to the cave as you scroll (that is the page, not an animation), but
   nothing in it moves on its own. */
@media (prefers-reduced-motion: reduce) {
  .bat-rain, .bcv-drip, .bat-signal, .btr { animation: none; }
}

/* ═════════════ Batman: the utility belt ═════════════ */
.bat-belt {
  padding: 0 var(--gutter); max-width: var(--maxw); margin: 0 0 3.4rem;
}

.bat-strap {
  position: relative; display: flex; align-items: stretch; gap: 6px;
  padding: 10px; border-radius: 8px;
  background: linear-gradient(180deg, #4a3b22, #2e2415 60%, #1d1710);
  box-shadow: inset 0 2px 0 rgba(255,255,255,.10), inset 0 -8px 14px rgba(0,0,0,.5), 0 22px 44px -28px #000;
}

.bat-strap::before, .bat-strap::after {  /* stitching */
  content: ""; position: absolute; left: 10px; right: 10px; height: 1px;
  background: repeating-linear-gradient(90deg, rgba(240,220,160,.35) 0 5px, transparent 5px 11px);
}

.bat-strap::before { top: 5px; }

.bat-strap::after  { bottom: 5px; }

.bat-pouch {
  position: relative; flex: 1 1 0; min-width: 0;
  padding: 0.9rem 0.7rem 0.8rem; border-radius: 5px; text-align: center;
  background: linear-gradient(180deg, #6b5730, #40331d);
  box-shadow: inset 0 2px 0 rgba(255,255,255,.14), inset 0 -6px 10px rgba(0,0,0,.45);
  transition: transform .35s var(--ease), background .35s;
}

.bat-pouch:hover { transform: translateY(-5px); background: linear-gradient(180deg, #7d6737, #4a3b22); }

.bat-pouch::before {                     /* the flap */
  content: ""; position: absolute; left: 8%; right: 8%; top: 5px; height: 34%;
  border-radius: 3px; background: linear-gradient(180deg, rgba(0,0,0,.28), transparent);
  border-bottom: 1px solid rgba(0,0,0,.4);
}

.bat-pouch b {
  position: relative; display: block; font-family: var(--serif); font-weight: 600;
  font-size: 0.86rem; color: #f0e4c0; line-height: 1.2;
}

.bat-pouch span {
  position: relative; display: block; margin-top: 0.25rem;
  font-family: var(--mono); font-size: 0.52rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: rgba(240,228,192,.6);
}

.bat-belt-cap {
  margin-top: 1rem; text-align: center;
  font-family: var(--mono); font-size: 0.6rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--mute);
}

@media (max-width: 720px) { .bat-strap { flex-wrap: wrap; } .bat-pouch { flex: 1 1 30%; } }
