/* ──────────────────────────────────────────────────────────────────────────
   motion-plus.css — the second motion layer

   motion.js owns ENTRANCES (words rising) and SCRUBS (scroll-as-timeline).
   This file owns the things that respond to the *pointer* rather than the
   scrollbar, plus the ambient movement that makes a page feel alive while
   it is sitting still.

   Everything here is additive: remove the file and the site still works,
   it is simply calmer. Everything also collapses to nothing under
   prefers-reduced-motion, which is at the bottom in one block rather than
   repeated per rule.
   ────────────────────────────────────────────────────────────────────────── */

/* ═══ 1 · ambient aurora behind every hero ════════════════════════════════
   Two slow blobs drifting on different periods, so the loop never visibly
   repeats. Pure CSS — no rAF, no scroll listener, no cost when offscreen.
   -4s on the second one stops them starting life stacked on each other. */

.hero, .ad-hero, .bk-hero, .bp-hero, .p-hero,
.page-hero, .sc-hero, .sh-hero, .sp-hero { position: relative; }

/* inset:0, not a negative inset. Bleeding the container past the hero to
   soften the edges widened the page by 15px and put a horizontal scrollbar
   on eight pages at phone width -- the blobs are already oversized and
   offset inside their own overflow:hidden, so the bleed bought nothing the
   blur was not already doing. */
.mp-aura {
  position: absolute; inset: 0;
  pointer-events: none; z-index: 0;
  overflow: hidden;
}
.mp-aura b {
  position: absolute; display: block;
  width: 46vw; height: 46vw; min-width: 320px; min-height: 320px;
  border-radius: 50%;
  filter: blur(68px);
  opacity: .34;
  will-change: transform;
}
.mp-aura b:nth-child(1) {
  left: -8%; top: -14%;
  background: radial-gradient(circle, rgba(212,135,78,.70), transparent 68%);
  animation: mp-drift-a 23s ease-in-out infinite alternate;
}
.mp-aura b:nth-child(2) {
  right: -10%; bottom: -18%;
  background: radial-gradient(circle, rgba(212,135,78,.62), transparent 68%);
  animation: mp-drift-b 31s ease-in-out infinite alternate;
  animation-delay: -4s;
}
@keyframes mp-drift-a {
  from { transform: translate3d(0,0,0) scale(1); }
  to   { transform: translate3d(9vw, 6vh, 0) scale(1.18); }
}
@keyframes mp-drift-b {
  from { transform: translate3d(0,0,0) scale(1.1); }
  to   { transform: translate3d(-11vw,-7vh,0) scale(.92); }
}
/* a dark hero needs the blobs hotter to read at all through the scrim */
.hero .mp-aura b { opacity: .5; }

/* keep the hero's own content above the glow */
.hero > *:not(.mp-aura):not(.hero-wall):not(.hero-scrim),
.p-hero > *:not(.mp-aura), .page-hero > *:not(.mp-aura),
.ad-hero > *:not(.mp-aura), .bk-hero > *:not(.mp-aura),
.bp-hero > *:not(.mp-aura), .sc-hero > *:not(.mp-aura),
.sh-hero > *:not(.mp-aura), .sp-hero > *:not(.mp-aura) { position: relative; z-index: 1; }

/* ═══ 2 · pointer tilt + sheen on cards ═══════════════════════════════════
   The tilt itself is written inline by motion-plus.js, because it has to be
   a live value. What lives here is the sheen: a soft light that tracks the
   cursor across the card face, which is what sells the surface as physical
   rather than as a rectangle that happens to move.

   The sheen is painted as the card's own background-image rather than as an
   overlay child. An overlay was the obvious build and the wrong one: a
   positioned child paints ABOVE the card's inline content, so the gradient
   washed over the headline, and fixing that would have meant forcing
   position/z-index onto every child of eight different card types -- which
   breaks any card that positions a child of its own. As a background layer
   it sits under all content by definition and cannot conflict with anything.

   --sheen is registered with @property purely so it can be transitioned;
   a plain custom property would snap from 0 to 1 and the light would
   appear and vanish with a click rather than fade. */

@property --sheen { syntax: "<number>"; initial-value: 0; inherits: false; }

/* No `transition` declaration here on purpose. Every card type already
   declares its own -- lift, shadow, border -- at the same specificity as
   [data-tilt], so adding one more would win or lose on source order alone
   and silently kill the card's hover ease on whichever pages lost. The JS
   writes an inline transition covering both --sheen and transform for the
   duration of the hover, and restores the spring-back on the way out. */
[data-tilt] {
  --mx: 50%; --my: 50%;
  background-image: radial-gradient(260px circle at var(--mx) var(--my),
                    rgba(255,255,255,calc(.80 * var(--sheen))), transparent 60%);
}
[data-tilt]:hover { --sheen: 1; }
/* the dark show tiles need light added, not white laid on top */
.show-tile[data-tilt] {
  background-image: radial-gradient(260px circle at var(--mx) var(--my),
                    rgba(232,201,110,calc(.30 * var(--sheen))), transparent 62%);
}

/* ═══ 3 · magnetic buttons ════════════════════════════════════════════════
   The button leans a few pixels toward the cursor before it is clicked.
   Tiny, and the single cheapest thing that makes a page feel expensive.
   The translate is inline; the spring back is here. */

[data-mag] { will-change: transform; }
[data-mag]:not(:hover) { transition: transform .5s cubic-bezier(.22,1.4,.4,1); }

/* ═══ 4 · cover wipe ══════════════════════════════════════════════════════
   79 covers appearing all at once is a wall. Wiping them in from the
   bottom, staggered by column, turns the grid into something that happens
   rather than something that is simply there. */

.mp-wipe { clip-path: inset(0 0 100% 0); opacity: 0;
  transition: clip-path 1s cubic-bezier(.22,1,.3,1),
              opacity .7s ease, transform 1s cubic-bezier(.22,1,.3,1);
  transform: scale(1.06); }
.mp-wipe.mp-in { clip-path: inset(0 0 0 0); opacity: 1; transform: none; }

/* ═══ 5 · sitewide scroll progress ════════════════════════════════════════
   motion.js only builds the bar on pages that have a scrub act. Styling it
   here as well means the plus layer can put one on every page without
   duplicating the rule. */

.m-progress {
  position: fixed; left: 0; top: 0; height: 2px; width: 0; z-index: 9999;
  background: linear-gradient(90deg, var(--sage), var(--gold));
  pointer-events: none;
}

/* ═══ 6 · link underline that draws itself ════════════════════════════════ */

.mp-ul { position: relative; }
.mp-ul::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px;
  background: currentColor; opacity: .5;
  transform: scaleX(0); transform-origin: right center;
  transition: transform .5s cubic-bezier(.22,1,.3,1);
}
.mp-ul:hover::after { transform: scaleX(1); transform-origin: left center; }

/* ═══ 7 · the quiet version ═══════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  .mp-aura { display: none; }
  [data-tilt] { background-image: none !important; transition: none; }
  .mp-wipe { clip-path: none; opacity: 1; transform: none; transition: none; }
  [data-mag], [data-tilt] { transition: none !important; transform: none !important; }
  .mp-ul::after { transition: none; }
}
/* Phones get the aura (it is free) but not the pointer work, which has no
   cursor to follow and only costs battery. */
@media (max-width: 859px) {
  [data-tilt] { background-image: none; }
  .mp-aura b { filter: blur(52px); opacity: .28; }
}

/* ═══ perf.py · cheaper ambient glow ═══════════════════════════════════════
   blur(68px) across a 46vw blob is a texture the size of the screen, and
   animating scale() forces it to be re-rasterised at every new size rather
   than just re-composited. Translate alone is a composited move. The hero
   already has 40 covers behind the scrim, so it does not need the glow at
   all -- that was the most expensive place it ran. */
.hero .mp-aura{display:none;}
.mp-aura b{filter:blur(54px);width:38vw;height:38vw;}
@keyframes mp-drift-a{
  from{transform:translate3d(0,0,0)} to{transform:translate3d(9vw,6vh,0)} }
@keyframes mp-drift-b{
  from{transform:translate3d(0,0,0)} to{transform:translate3d(-11vw,-7vh,0)} }

/* ═══ 2026-10-25 · "the website is lagging a lot" ═══════════════════════════
   Two 38vw blobs under blur(54px) drifting forever meant the GPU re-blurred a
   screen-sized texture on every frame of every page, for the whole visit. A
   still glow looks the same at a glance and costs one raster at load. */
.mp-aura b{animation:none!important;will-change:auto;}
