/* ==========================================================================
   ANIMATIONS + SPECIALTY COMPONENTS
   ========================================================================== */

/* ---- Scroll reveal -----------------------------------------------------
   The hidden state is gated behind html.js, which the pre-paint guard sets.
   Content is therefore visible by default: if a script fails, an observer
   never fires, or the page is printed, nothing disappears. Only a browser
   that is definitely running our JS ever hides anything.
   ------------------------------------------------------------------------ */
html.js .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
}
html.js .reveal.is-in { opacity: 1; transform: none; }

html.no-motion .reveal { opacity: 1; transform: none; transition: none; }

@media print {
  .reveal { opacity: 1 !important; transform: none !important; }
}

/* ==========================================================================
   COMPONENT: Animated Blur Number
   Digits that change blur and slide; unchanged digits hold still.
   ========================================================================== */
.blur-num-root {
  display: inline-flex;
  align-items: baseline;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.blur-num-slot {
  position: relative;
  display: inline-block;
  overflow: hidden;
}
.blur-num-layer {
  display: inline-block;
  will-change: transform, opacity, filter;
}
.blur-num-out {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

@keyframes bnSlideIn {
  from { transform: translateY(0.55em);  opacity: 0; filter: blur(14px); }
  to   { transform: translateY(0);       opacity: 1; filter: blur(0);    }
}
@keyframes bnSlideOut {
  from { transform: translateY(0);       opacity: 1; filter: blur(0);    }
  to   { transform: translateY(-0.55em); opacity: 0; filter: blur(14px); }
}

.blur-num-in       { animation: bnSlideIn  var(--bn-dur, 480ms) cubic-bezier(0.16, 1, 0.3, 1) both; }
.blur-num-out-anim { animation: bnSlideOut var(--bn-dur, 480ms) cubic-bezier(0.4, 0, 1, 1) both; }

@media (prefers-reduced-motion: reduce) {
  .blur-num-in, .blur-num-out-anim { animation: none; }
}

/* ==========================================================================
   COMPONENT: Container Scroll Animation
   The open issue spread starts tilted back and flattens as you scroll.
   ========================================================================== */
.csa-track {
  height: 52rem;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  position: relative;
  padding: var(--sp-5) 1.25rem 0;
  overflow: hidden;
  background: var(--sand-2);
}
.csa-inner {
  width: 100%;
  max-width: 980px;
  position: sticky;
  top: 7vh;
  perspective: 1100px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-4);
}
.csa-title { text-align: center; will-change: transform; }
.csa-title .eyebrow { justify-content: center; }
.csa-title h2 { font-size: var(--step-4); }

.csa-card-wrap {
  width: 100%;
  transform-origin: center top;
  transform: rotateX(20deg);
  will-change: transform;
  border-radius: 20px;
  border: 3px solid rgba(28,23,20,.28);
  background: var(--ink);
  padding: 10px;
  box-shadow:
    0 9px 20px rgba(28,23,20,.20),
    0 37px 37px rgba(28,23,20,.16),
    0 84px 50px rgba(28,23,20,.10),
    0 149px 60px rgba(28,23,20,.04);
}
.csa-card-inner {
  width: 100%;
  height: 440px;
  border-radius: 12px;
  overflow: hidden;
  background: var(--paper);
  display: flex;
}
.csa-card-inner img { width: 100%; height: 100%; object-fit: cover; }

/* The spread mock inside the frame — two pages of the actual publication look */
.csa-spread { display: flex; width: 100%; height: 100%; }
.csa-spread__half {
  flex: 1;
  position: relative;
  overflow: hidden;
  background: var(--paper);
}
.csa-spread__half + .csa-spread__half { border-left: 1px solid var(--rule); }
.csa-spread__half::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  width: 34px;
  pointer-events: none;
}
.csa-spread__half:first-child::after { right: 0; background: linear-gradient(to left, rgba(28,23,20,.16), transparent); }
.csa-spread__half:last-child::after  { left: 0;  background: linear-gradient(to right, rgba(28,23,20,.16), transparent); }
.csa-spread__half img { width: 100%; height: 100%; object-fit: cover; }

@media (max-width: 820px) {
  .csa-track { height: 46rem; padding-top: var(--sp-5); }
  .csa-card-inner { height: 250px; }
  .csa-inner { top: 9vh; }
}

@media (prefers-reduced-motion: reduce) {
  .csa-card-wrap { transform: none !important; }
  .csa-title { transform: none !important; }
}
html.no-motion .csa-card-wrap { transform: none !important; }
html.no-motion .csa-title { transform: none !important; }

/* ==========================================================================
   COMPONENT: Background Paths
   Slow-drifting SVG curves that give a flat dark band some texture.
   ========================================================================== */
.bg-paths {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
.bg-paths svg { width: 100%; height: 100%; }
.bg-paths path {
  fill: none;
  stroke: var(--citrus);
  stroke-width: 1;
  opacity: .10;
  stroke-dasharray: 1400;
  stroke-dashoffset: 1400;
  animation: bpDraw var(--bp-dur, 26s) linear infinite;
  animation-delay: var(--bp-delay, 0s);
}
@keyframes bpDraw {
  0%   { stroke-dashoffset: 1400; opacity: 0; }
  12%  { opacity: .12; }
  85%  { opacity: .10; }
  100% { stroke-dashoffset: -1400; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .bg-paths path { animation: none; stroke-dashoffset: 0; opacity: .08; }
}
html.no-motion .bg-paths path { animation: none; stroke-dashoffset: 0; opacity: .08; }

/* ==========================================================================
   COMPONENT: Display Cards (3D stacked)
   Ad sizes fanned as a stack; hover lifts one out of the fan.
   ========================================================================== */
.dcards {
  display: grid;
  place-items: center;
  perspective: 1000px;
  padding-block: var(--sp-4) var(--sp-5);
}
/* The stack is taller than one card: the third card is offset 92px down, and
   the skew adds a little more. Size the container for the whole fan so it
   cannot spill onto the caption below it. */
.dcards__stack {
  position: relative;
  width: min(100%, 420px);
  height: 356px;
  transform-style: preserve-3d;
  margin-left: -46px;
}
.dcard {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 240px;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: var(--sp-3);
  border: var(--bw) solid var(--line);
  border-radius: var(--r);
  background: var(--white);
  box-shadow: var(--sh-2);
  transform: skewY(-8deg) translate(var(--dc-x, 0), var(--dc-y, 0));
  transition: transform var(--dur) var(--ease), filter var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
  /* Cards stay fully opaque. Translucent cards let the text of the card behind
     bleed through and the whole stack becomes unreadable. */
  opacity: 1;
}
.dcard:nth-child(1) { --dc-x: 0px;   --dc-y: 0px;   z-index: 3; }
.dcard:nth-child(2) { --dc-x: 46px;  --dc-y: 46px;  z-index: 2; }
.dcard:nth-child(3) { --dc-x: 92px;  --dc-y: 92px;  z-index: 1; }

/* Only the cards BEHIND the front one desaturate. Greying the front card too
   drained the whole stack — the badge and price lost their colour. */
.dcard:nth-child(2),
.dcard:nth-child(3) { filter: grayscale(1) brightness(.99); }

.dcard:hover, .dcard:focus-within {
  filter: none;
  transform: skewY(-8deg) translate(var(--dc-x, 0), calc(var(--dc-y, 0px) - 26px));
  z-index: 5;
  border-color: var(--coral);
  box-shadow: var(--sh-3);
}

.dcard__badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  align-self: flex-start;
  background: var(--citrus);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.25rem 0.6rem;
  border: var(--bw-2) solid var(--line);
  border-radius: var(--r-pill);
}
.dcard h3 { font-size: var(--step-1); }
.dcard p { font-size: 0.9rem; color: var(--muted); }
.dcard__price {
  margin-top: auto;
  font-family: var(--mono);
  font-size: 1.05rem;
  color: var(--coral-dark);
}

@media (max-width: 620px) {
  .dcards__stack { height: 302px; margin-left: -26px; }
  .dcard { height: 210px; }
  .dcard:nth-child(2) { --dc-x: 26px; --dc-y: 34px; }
  .dcard:nth-child(3) { --dc-x: 52px; --dc-y: 68px; }
}
@media (prefers-reduced-motion: reduce) {
  .dcard { transition: none; }
}
