/* ==========================================================================
   Scroll-triggered entry motion — homepage only, below the cover.
   Two treatments: a plain fade + rise for supporting content, and a
   clip-path wipe for major (46px+) display headlines, where the
   reference system already puts its visual weight. Everything triggers
   once via IntersectionObserver (js/motion.js) and never replays — a
   settle-in on first view, not an ambient loop.

   Background tone shifts between sections are pure CSS: a short gradient
   blend band at each section's top edge, fading from the previous
   section's tone down to transparent. No scroll-position math, no JS.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  .reveal {
    opacity: 0;
    transform: translateY(26px);
    transition: opacity 0.55s cubic-bezier(0.22, 0.61, 0.36, 1),
                transform 0.55s cubic-bezier(0.22, 0.61, 0.36, 1);
  }

  .reveal.is-visible {
    opacity: 1;
    transform: translateY(0);
  }

  /* Major display headlines (46px+) wipe left-to-right instead of
     fading — the reference treats display type as the dominant visual
     element, so it gets the more deliberate reveal. Used sparingly: only
     section headlines, never body text.

     The clip-path lives on an inner wrapper, not the observed .reveal-wipe
     element itself: a fully clip-path'd target collapses to a zero-area
     bounding box and never reports as intersecting (the same issue
     js/main.js's hero-mark reveal already works around), which would
     permanently deadlock the reveal. Observing the un-clipped outer
     element sidesteps that. */
  .reveal-wipe__inner {
    display: block;
    clip-path: inset(0 100% 0 0);
    transition: clip-path 0.48s cubic-bezier(0.22, 0.61, 0.36, 1);
  }

  .reveal-wipe.is-visible .reveal-wipe__inner {
    clip-path: inset(0 0% 0 0);
  }

  /* clip-path clips an element's own overflow to its own box even at a
     0%/no-op inset — unlike plain overflow, which defaults to visible.
     The hero's "& Object" line is deliberately wider than its flex
     column (white-space:nowrap forces exactly two rows regardless of
     available width — see .hero__line), so at the hero's normal,
     block-level 100%-of-container width the wipe would clip the
     overflow off instead of leaving it to spill past the column like it
     does without a clip-path. Sizing the wrapper to its own content
     width keeps the clip region large enough to contain the overflow. */
  .hero .reveal-wipe__inner {
    width: max-content;
  }

  /* Grid/row stagger — direct .reveal children of a .reveal-group pick
     up a small transition-delay by position, so a row assembles as a
     quick cascade rather than appearing all at once. All children still
     become visible together (same intersection moment); the delay alone
     creates the stagger. */
  .reveal-group > .reveal:nth-child(1) { transition-delay: 0ms; }
  .reveal-group > .reveal:nth-child(2) { transition-delay: 80ms; }
  .reveal-group > .reveal:nth-child(3) { transition-delay: 160ms; }
  .reveal-group > .reveal:nth-child(4) { transition-delay: 240ms; }
  .reveal-group > .reveal:nth-child(5) { transition-delay: 320ms; }
  .reveal-group > .reveal:nth-child(6) { transition-delay: 400ms; }

  /* Directional variants — same fade+rise as .reveal, but sliding in
     from the side instead of from below. Used on the broken-grid
     homepage sections so an element's entrance direction can echo
     which side of the grid it sits on/breaks toward, rather than every
     element rising the same way regardless of its position. Declared
     after .reveal so the transform override wins at equal specificity. */
  .reveal--left,
  .reveal--right {
    transform: translateX(0);
  }

  .reveal--left {
    transform: translateX(-36px);
  }

  .reveal--right {
    transform: translateX(36px);
  }

  .reveal--left.is-visible,
  .reveal--right.is-visible {
    transform: translateX(0);
  }

  /* Image reveal-through-mask — a large image clips in from one edge
     while easing down from a slight overscale, instead of a plain fade.
     Meant for the image/SVG itself (not its bordered frame), so the
     frame's own border/background stays put and only the artwork
     inside reveals. The frame needs overflow:hidden (card__frame and
     shop-item__figure already have it) to contain the overscaled state. */
  .reveal-img {
    opacity: 0;
    clip-path: inset(0 0 0 14%);
    transform: scale(1.06);
    transition: opacity 0.65s cubic-bezier(0.22, 0.61, 0.36, 1),
                clip-path 0.7s cubic-bezier(0.22, 0.61, 0.36, 1),
                transform 0.7s cubic-bezier(0.22, 0.61, 0.36, 1);
  }

  .reveal-img.is-visible {
    opacity: 1;
    clip-path: inset(0 0 0 0%);
    transform: scale(1);
  }
}

/* Reduced motion: content is simply present — no fade, no clip, no delay. */
@media (prefers-reduced-motion: reduce) {
  .reveal,
  .reveal-wipe__inner,
  .reveal-img {
    opacity: 1;
    transform: none;
    clip-path: none;
  }
}

/* No JS: js/motion.js is what adds .is-visible, so without it these
   elements — including headline text — would stay permanently hidden.
   Show everything plainly instead. */
@media (scripting: none) {
  .reveal,
  .reveal-img,
  .reveal-wipe__inner {
    opacity: 1;
    transform: none;
    clip-path: none;
  }
}

/* -------------------------------------------------------------------------
   Background tone transitions
   ------------------------------------------------------------------------- */
.section--blend {
  position: relative;
}

.section--blend::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 140px;
  background: linear-gradient(to bottom, var(--blend-from), transparent);
  pointer-events: none;
}
