/* ─── effects layer ──────────────────────────────────────────────────────
   The WebGL field, plus the shine that sits on top of it: swept metal on the
   display type, pointer-tracked holo on the cards, and slow drift on the
   objects. Everything here is decoration — it degrades to the flat dark
   design if WebGL or motion is unavailable.
   ───────────────────────────────────────────────────────────────────────── */

/* The ground moves to <html> so <body> can be transparent and let the field
   through. Without this the canvas is painted over by the body fill. */
html {
  background: var(--ink);
}

body {
  background: transparent;
}

.glfield {
  position: fixed;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  /* screen keeps the field additive over the ink so it reads as light in the
     room rather than a coloured sheet laid on top */
  mix-blend-mode: screen;
}

/* content clears the field */
.shell,
.rail,
.marquee,
.foot {
  position: relative;
  z-index: 2;
}

/* the CSS grain rides above the field, not under it */
.grain {
  z-index: 901;
}

/* ── swept metal on the display type ───────────────────────────────────────
   A highlight travels across the letterforms. The base stays bone so the
   type never loses contrast at the dark end of the sweep. */
@keyframes sweep {
  0%   { background-position: -140% 0; }
  100% { background-position: 240% 0; }
}

/* ── the ink guard ──
   Humane's caps rise above the line box: the face measures 0.706em of ink
   over the baseline, and at our display line-heights (0.72–0.76) the baseline
   sits close enough to the top that the caps overhang the element's own box
   by roughly 0.05em (0.06em at the tightest line-height we use).

   That overhang is invisible with a plain colour, but `background-clip: text`
   paints only inside the box — so the tops of the letters get no gradient and
   read as CUT OFF. Reserving the ink as padding and pulling the box back up
   by the same amount fixes the paint without moving a single glyph.

   Any new Humane element that takes a text gradient needs this too. */
.wordmark span,
.card__numeral .fig {
  padding-top: 0.1em;
  margin-top: -0.1em;
}

/* .sheen headings carry inline margin-top at some call sites, which would win
   over a negative margin here — so this one pays the padding back with
   `translate` instead. It is a separate property from `transform`, so it does
   not disturb any transform these headings already have, and the background
   box travels with the glyphs, which is what keeps the gradient aligned. */
.sheen {
  padding-top: 0.1em;
  translate: 0 -0.1em;
}

/* The hero's glyphs live in per-letter spans, so the gradient has to be on
   the spans — `background-clip: text` clips an element's background to its
   OWN text, and the h1 has none. Staggering by --i walks the highlight
   across the wordmark instead of flashing every letter at once. */
.wordmark span {
  background-image: linear-gradient(
    100deg,
    var(--bone) 0%,
    var(--bone) 30%,
    #ffffff 42%,
    color-mix(in srgb, var(--mint) 60%, #ffffff) 50%,
    color-mix(in srgb, #c9a6ff 50%, #ffffff) 58%,
    var(--bone) 72%,
    var(--bone) 100%
  );
  background-size: 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: strike-up 1.1s var(--ease) forwards,
             sweep 5.5s linear infinite calc(var(--i) * 90ms);
  animation-delay: calc(var(--i) * 55ms + 150ms), calc(var(--i) * 90ms);
}

.sheen {
  background-image: linear-gradient(
    100deg,
    var(--bone) 0%,
    var(--bone) 32%,
    #ffffff 44%,
    color-mix(in srgb, var(--mint) 55%, #ffffff) 50%,
    color-mix(in srgb, var(--epic, #c9a6ff) 45%, #ffffff) 56%,
    var(--bone) 68%,
    var(--bone) 100%
  );
  background-size: 260% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: sweep 7.5s linear infinite;
}

.d-hero {
  filter: drop-shadow(0 0 60px rgba(59, 232, 196, 0.22))
          drop-shadow(0 0 120px rgba(125, 57, 235, 0.14));
}

/* ── objects glow ────────────────────────────────────────────────────────── */
.rung .gem {
  filter: drop-shadow(0 0 22px color-mix(in srgb, var(--tier) 55%, transparent))
    drop-shadow(0 0 46px color-mix(in srgb, var(--tier) 25%, transparent));
  animation: float 7s ease-in-out infinite;
}

.rung:nth-child(2) .gem { animation-delay: -1.1s; }
.rung:nth-child(3) .gem { animation-delay: -2.3s; }
.rung:nth-child(4) .gem { animation-delay: -3.4s; }
.rung:nth-child(5) .gem { animation-delay: -4.6s; }

@keyframes float {
  0%, 100% { transform: translateY(0) scale(var(--gem-s, 1)); }
  50%      { transform: translateY(-7px) scale(var(--gem-s, 1)); }
}

.pill .dot {
  animation: pulse 2.6s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { box-shadow: 0 0 8px var(--mint); opacity: 0.85; }
  50%      { box-shadow: 0 0 18px var(--mint), 0 0 34px var(--mint); opacity: 1; }
}

.seal {
  animation: spin 14s linear infinite, float 8s ease-in-out infinite;
  filter: drop-shadow(0 0 26px rgba(59, 232, 196, 0.45));
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* ── the cards catch the light ───────────────────────────────────────────── */
.card {
  box-shadow:
    0 36px 80px -24px rgba(0, 0, 0, 0.95),
    0 0 var(--glow-r) var(--glow);
}

/* a second, iridescent pass over the frame that tracks the pointer */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.6s var(--ease);
  background: linear-gradient(
    calc(var(--holo-deg, 105) * 1deg),
    transparent 34%,
    rgba(59, 232, 196, 0.16) 44%,
    rgba(255, 255, 255, 0.22) 50%,
    rgba(125, 57, 235, 0.18) 57%,
    transparent 68%
  );
  mix-blend-mode: screen;
}

.card.is-lit::after,
.card:hover::after {
  opacity: 1;
}

/* legendary keeps a permanent oil-slick crawl */
.card[data-tier="legendary"]::after {
  opacity: 0.55;
}

/* ── the rail stage gets depth behind the cards ──────────────────────────── */
.rail__stage::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    58% 42% at 50% 50%,
    rgba(255, 255, 255, 0.05),
    transparent 70%
  );
}

/* ── the boss panel's edge light breathes ────────────────────────────────── */
.boss::before {
  animation: edge 5.5s ease-in-out infinite;
}

@keyframes edge {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 1; }
}

/* ── the call to action ──────────────────────────────────────────────────── */
.cta:not([aria-disabled]) {
  box-shadow: 0 0 0 rgba(198, 255, 51, 0);
  animation: cta 3.2s ease-in-out infinite;
}

@keyframes cta {
  0%, 100% { box-shadow: 0 10px 40px -14px rgba(198, 255, 51, 0.5); }
  50%      { box-shadow: 0 10px 60px -10px rgba(198, 255, 51, 0.85); }
}

/* ── reduced motion / no WebGL ───────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .glfield { display: none; }
  .wordmark span,
  .d-hero,
  .sheen {
    animation: none;
    background: none;
    -webkit-text-fill-color: var(--bone);
    color: var(--bone);
  }
  .rung .gem,
  .pill .dot,
  .seal,
  .boss::before,
  .cta:not([aria-disabled]) {
    animation: none;
  }
}
