/**
 * Island Dental Studio — motion.
 *
 *   27  Entrance reveal
 *   28  Rotating image frame
 *   29  Reduced motion
 *
 * ── How the reveal system avoids hiding anything it cannot bring back ──
 *
 * Nothing in this file hides content on its own. Every hidden state is scoped
 * to `html.ids-anim`, a class added by four lines of inline script in <head>
 * (see ids_motion_bootstrap() in functions.php) that run before the page
 * paints, and removed again by that same script if the front-end bundle has not
 * reported for duty within two and a half seconds.
 *
 * So: JavaScript off, blocked, still loading, or throwing — the class is absent
 * and the site renders exactly as it would with this file deleted. The
 * enhancement can only ever be added, never left half-applied.
 *
 * ── What counts as one thing arriving ──
 *
 * The unit of reveal is a *content block*, not a section. §27 names the
 * compositional wrappers of the site — the container, a split, a heading block,
 * a card grid — and the rule is one line long:
 *
 *     a reveal item is a direct child of a wrapper, and is not a wrapper itself
 *
 * which walks the page one level at a time until it reaches something with
 * content in it. An eyebrow, a heading, a paragraph, an image, one card. Each
 * is then observed on its own and arrives when *it* reaches the reveal line, so
 * a heading entering the viewport no longer starts three cards that are still
 * a screen below it.
 *
 * Two things fall out of that rule for free. A wrapper is never itself animated
 * — it is excluded by the `:not()` — so section bands, hero photographs and CTA
 * backgrounds never move. And a child can never inherit its parent's movement,
 * because a parent that has children to reveal is a wrapper and is therefore
 * standing still.
 *
 * assets/js/modules/reveal.js holds the same list. They must agree.
 */

/* ═══════════════════════════════════════════════════════
   27  ENTRANCE REVEAL
   ═══════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: no-preference) {

    /**
     * The wrappers. Anything listed here is descended into rather than
     * animated: page and panel containers first, then the compositional
     * wrappers, then the repeating groups whose children are the cards.
     */
    html.ids-anim :is(
        .ids-container, .ids-bleed, .ids-cta__body, .ids-hero__content, .ids-hero__copy,
        .ids-section-head, .ids-section-head-row, .ids-intro-row, .ids-intro-row__lead, .ids-intro-row__copy,
        .ids-split, .ids-split__body, .ids-rail, .ids-rail__main, .ids-find,
        .ids-legal__layout, .ids-legal__body, .ids-legal__section, .ids-tx-copy, .ids-vt,
        .ids-grid, .ids-steps, .ids-pcards, .ids-trust, .ids-accordion,
        .ids-fee-groups, .ids-fee-group, .ids-fee-list, .ids-credentials, .ids-find__points
    ) > *:not(:is(
        .ids-container, .ids-bleed, .ids-cta__body, .ids-hero__content, .ids-hero__copy,
        .ids-section-head, .ids-section-head-row, .ids-intro-row, .ids-intro-row__lead, .ids-intro-row__copy,
        .ids-split, .ids-split__body, .ids-rail, .ids-rail__main, .ids-find,
        .ids-legal__layout, .ids-legal__body, .ids-legal__section, .ids-tx-copy, .ids-vt,
        .ids-grid, .ids-steps, .ids-pcards, .ids-trust, .ids-accordion,
        .ids-fee-groups, .ids-fee-group, .ids-fee-list, .ids-credentials, .ids-find__points
    )) {
        opacity: 0;
        transform: translateY(var(--ids-reveal-y));
    }

    /**
     * A sticky column fades but does not travel.
     *
     * A transform on an element makes it a containing block, and a
     * `position: sticky` box that is itself being moved drifts against the
     * scroll while the transition runs. Declared straight after the rule above,
     * at the same specificity, so source order settles it.
     */
    html.ids-anim :is(.ids-rail, .ids-legal__layout, .ids-split, .ids-container)
        > :is(.ids-rail__panel, .ids-sticky-panel) {
        transform: none;
    }

    /**
     * Arrival. The delay is written per element by the reveal module: items
     * that reach the line in the same frame — a row of cards — are counted out
     * one after another; anything arriving on its own has no delay at all.
     */
    html.ids-anim :is(
        .ids-container, .ids-bleed, .ids-cta__body, .ids-hero__content, .ids-hero__copy,
        .ids-section-head, .ids-section-head-row, .ids-intro-row, .ids-intro-row__lead, .ids-intro-row__copy,
        .ids-split, .ids-split__body, .ids-rail, .ids-rail__main, .ids-find,
        .ids-legal__layout, .ids-legal__body, .ids-legal__section, .ids-tx-copy, .ids-vt,
        .ids-grid, .ids-steps, .ids-pcards, .ids-trust, .ids-accordion,
        .ids-fee-groups, .ids-fee-group, .ids-fee-list, .ids-credentials, .ids-find__points
    ) > .is-in {
        opacity: 1;
        transform: none;
        transition:
            opacity var(--ids-reveal-dur) var(--ids-ease) var(--ids-reveal-delay, 0ms),
            transform var(--ids-reveal-dur) var(--ids-ease) var(--ids-reveal-delay, 0ms);
    }

    /* The first screenful: the reader is waiting on this rather than scrolling
       towards it, so it plays at a pace that does not hold the page up. */
    html.ids-anim .is-in--prompt { --ids-reveal-dur: var(--ids-reveal-dur-prompt); }

    /* Content that arrived because someone asked for it — a filtered result.
       Slow motion here reads as the site having stalled. */
    html.ids-anim .is-in--quick { --ids-reveal-dur: var(--ids-reveal-dur-quick); }
}

/* ═══════════════════════════════════════════════════════
   28  ROTATING IMAGE FRAME
   Several photographs sharing one media frame, cross-fading between them.
   ═══════════════════════════════════════════════════════ */

/**
 * Every image is absolutely positioned and fills the frame (the split media
 * rules in components.css already do this), so the frame's height is its own
 * and no swap can move the page. The only thing that changes is which image is
 * opaque.
 */
.ids-flip__img {
    opacity: 0;
    transition: opacity var(--ids-flip-dur) var(--ids-ease);
}
/* Set on the first image by the renderer, so with JavaScript off — or before
   the module runs — the frame is simply the first photograph. */
.ids-flip__img.is-current { opacity: 1; }

/* ═══════════════════════════════════════════════════════
   29  REDUCED MOTION
   The global rule in main.css §09 already collapses transitions. These are the
   two effects that are positions rather than transitions, and so need saying.
   ═══════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
    /* Whatever the parallax module may have written before the preference was
       read, the image sits still, centred in its frame. */
    .ids-cta__panel[data-ids-parallax] .ids-cta__img,
    .ids-stories[data-ids-parallax] .ids-stories__img { transform: none; }

    /* The frame holds its first photograph; the module does not rotate it. */
    .ids-flip__img { transition: none; }
}
