/**
 * Honey King page transitions.
 *
 * Entering: a staggered cascade - the content block fades in, its own children
 *           rise in sequence, then the product/COA cards follow one after another.
 * Leaving:  the outgoing page fades out before navigating.
 *
 * WHY THE ENTRANCE IS JS-GATED
 * A plain `animation` on load looked flat, and turning the numbers up would not
 * have fixed it. CSS animations start when styles resolve, but these pages have
 * render-blocking web fonts and ~250KB of inline CSS, so first paint lands late:
 * measured first-contentful-paint of 360ms on lab results and 312ms on the
 * landing page, against an animation starting at ~0ms. It was already over by the
 * time pixels appeared. page-transition.js applies the initial state up front and
 * triggers the animation after first paint, which is the only way to guarantee
 * the visitor sees it.
 *
 * WHY THE CLASSES ARE REMOVED AFTERWARDS
 * The grids are rendered by JavaScript and re-rendered on every filter change,
 * region switch and search keystroke. If the trigger class stayed on <html>, each
 * of those re-renders would re-run the cascade on freshly inserted cards - a
 * cascade every keystroke. page-transition.js removes both classes once the
 * entrance has finished, so the animation is strictly a page-load effect.
 *
 * TRANSFORM SAFETY
 * transform is applied to content blocks, their children, and grid cards - never
 * to <body>. A transform on <body> would make it a containing block for
 * `position: fixed` descendants and break the sticky header, the fixed region
 * backgrounds, the mobile drawer and all eleven modal overlays. Those live as
 * siblings of the content, and these subtrees were verified to contain no fixed
 * or sticky descendants on any of the four pages.
 *
 * Not the View Transitions API: cross-document @view-transition was implemented
 * and abandoned because an unskipped transition breaks programmatic scrolling on
 * the next document loaded - arriving at index.html#locator ended at scrollY 0
 * instead of 4608.
 */

/* ---- keyframes ---------------------------------------------------------- */

@keyframes hk-block-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes hk-item-rise {
    from {
        opacity: 0;
        transform: translate3d(0, 18px, 0);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

@keyframes hk-page-fade-out {
    from { opacity: 1; }
    to   { opacity: 0; }
}

/* ---- initial state ------------------------------------------------------
   Applied only under .hk-anim, which page-transition.js adds. Without JS the
   class never appears and everything renders at normal opacity.

   The homepage keeps its sections in <main id="main-content"> and animates them
   exactly like sections on <body>, not like the journal's <main> further down.
   :where() adds no specificity, so these rules rank the same either way. */

html.hk-anim body > .container,
html.hk-anim body > section,
html.hk-anim body > :where(#main-content) > section,
html.hk-anim body > footer {
    opacity: 0;
}

html.hk-anim body > .container > *,
html.hk-anim body > section > *,
html.hk-anim body > :where(#main-content) > section > *,
html.hk-anim #product-grid > *,
html.hk-anim #products-grid > *,
html.hk-anim #coa-grid > * {
    opacity: 0;
    transform: translate3d(0, 18px, 0);
}

/* ---- the cascade -------------------------------------------------------- */

html.hk-anim-ready body > .container,
html.hk-anim-ready body > section,
html.hk-anim-ready body > :where(#main-content) > section,
html.hk-anim-ready body > footer {
    animation: hk-block-in 240ms ease-out both;
}

/* Direct children of a content block: back bar, headings, filter rows, the grid
   itself. Six steps of 70ms is enough for the visible hierarchy on every page;
   anything past the sixth child shares the last delay rather than trailing off. */
html.hk-anim-ready body > .container > *,
html.hk-anim-ready body > section > *,
html.hk-anim-ready body > :where(#main-content) > section > * {
    animation: hk-item-rise 460ms cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: 350ms;
}

html.hk-anim-ready body > .container > *:nth-child(1),
html.hk-anim-ready body > section > *:nth-child(1),
html.hk-anim-ready body > :where(#main-content) > section > *:nth-child(1) { animation-delay: 0ms; }
html.hk-anim-ready body > .container > *:nth-child(2),
html.hk-anim-ready body > section > *:nth-child(2),
html.hk-anim-ready body > :where(#main-content) > section > *:nth-child(2) { animation-delay: 70ms; }
html.hk-anim-ready body > .container > *:nth-child(3),
html.hk-anim-ready body > section > *:nth-child(3),
html.hk-anim-ready body > :where(#main-content) > section > *:nth-child(3) { animation-delay: 140ms; }
html.hk-anim-ready body > .container > *:nth-child(4),
html.hk-anim-ready body > section > *:nth-child(4),
html.hk-anim-ready body > :where(#main-content) > section > *:nth-child(4) { animation-delay: 210ms; }
html.hk-anim-ready body > .container > *:nth-child(5),
html.hk-anim-ready body > section > *:nth-child(5),
html.hk-anim-ready body > :where(#main-content) > section > *:nth-child(5) { animation-delay: 280ms; }

/* Cards inside the grids, which is where the cascade actually reads. Capped at
   eight steps: a fifty-card catalogue must not take five seconds to arrive, so
   later cards share the eighth delay and simply come in together. */
html.hk-anim-ready #product-grid > *,
html.hk-anim-ready #products-grid > *,
html.hk-anim-ready #coa-grid > * {
    animation: hk-item-rise 440ms cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: 505ms;
}

html.hk-anim-ready #product-grid > *:nth-child(1),
html.hk-anim-ready #products-grid > *:nth-child(1),
html.hk-anim-ready #coa-grid > *:nth-child(1) { animation-delay: 120ms; }
html.hk-anim-ready #product-grid > *:nth-child(2),
html.hk-anim-ready #products-grid > *:nth-child(2),
html.hk-anim-ready #coa-grid > *:nth-child(2) { animation-delay: 175ms; }
html.hk-anim-ready #product-grid > *:nth-child(3),
html.hk-anim-ready #products-grid > *:nth-child(3),
html.hk-anim-ready #coa-grid > *:nth-child(3) { animation-delay: 230ms; }
html.hk-anim-ready #product-grid > *:nth-child(4),
html.hk-anim-ready #products-grid > *:nth-child(4),
html.hk-anim-ready #coa-grid > *:nth-child(4) { animation-delay: 285ms; }
html.hk-anim-ready #product-grid > *:nth-child(5),
html.hk-anim-ready #products-grid > *:nth-child(5),
html.hk-anim-ready #coa-grid > *:nth-child(5) { animation-delay: 340ms; }
html.hk-anim-ready #product-grid > *:nth-child(6),
html.hk-anim-ready #products-grid > *:nth-child(6),
html.hk-anim-ready #coa-grid > *:nth-child(6) { animation-delay: 395ms; }
html.hk-anim-ready #product-grid > *:nth-child(7),
html.hk-anim-ready #products-grid > *:nth-child(7),
html.hk-anim-ready #coa-grid > *:nth-child(7) { animation-delay: 450ms; }

/* ---- product image morph ------------------------------------------------
   product-morph.js adds .hk-morph-pending during head parsing when the visitor
   arrived by tapping a product card.

   The cascade is suppressed here rather than tuned. On the product page the hero
   image is nested inside the same block as the info column, so the cascade would
   be animating the hero's own ancestors - and a transformed ancestor changes what
   getBoundingClientRect reports, which would make the hero's measured destination
   wrong and land the FLIP in the wrong place. !important is needed because the
   cascade rules above match with equal specificity. */

html.hk-morph-pending body > .container,
html.hk-morph-pending body > .container > *,
html.hk-morph-pending body > section,
html.hk-morph-pending body > :where(#main-content) > section,
html.hk-morph-pending body > section > *,
html.hk-morph-pending body > :where(#main-content) > section > *,
html.hk-morph-pending body > footer {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
}

/* The parts that are NOT ancestors of the hero still rise in behind it, which is
   the choreography from the design preview: hero flies, page builds behind. */
html.hk-morph-pending .back-bar,
html.hk-morph-pending .product-info-col {
    animation: hk-item-rise 460ms cubic-bezier(0.16, 1, 0.3, 1) both !important;
    animation-delay: 180ms !important;
    opacity: 1;
}

/* ---- leaving ------------------------------------------------------------
   Uses its own animation rather than a transition: the entrance animation's
   fill-mode `both` wins over a transition in the cascade, so clearing it and
   setting opacity in one style change left no start value to interpolate from
   and the page snapped straight to blank. */

html.hk-leaving body {
    animation: hk-page-fade-out 160ms ease-in both;
}

html.hk-leaving body > .container,
html.hk-leaving body > section,
html.hk-leaving body > :where(#main-content) > section,
html.hk-leaving body > footer,
html.hk-leaving body > .container > *,
html.hk-leaving body > section > *,
html.hk-leaving body > :where(#main-content) > section > *,
html.hk-leaving #product-grid > *,
html.hk-leaving #products-grid > *,
html.hk-leaving #coa-grid > * {
    animation: none;
    opacity: 1;
    transform: none;
}

/* ---- reduced motion -----------------------------------------------------
   "Reduce motion" asks for less *movement* - translation, parallax, scaling -
   not a completely static page. An opacity fade is not a vestibular trigger, so
   the cascade is kept as a staggered cross-fade with every transform removed.
   The exit fade above is opacity-only and therefore kept as well. */

@media (prefers-reduced-motion: reduce) {
    html.hk-anim body > .container > *,
    html.hk-anim body > section > *,
    html.hk-anim body > :where(#main-content) > section > *,
    html.hk-anim #product-grid > *,
    html.hk-anim #products-grid > *,
    html.hk-anim #coa-grid > * {
        transform: none;
    }

    html.hk-anim-ready body > .container > *,
    html.hk-anim-ready body > section > *,
    html.hk-anim-ready body > :where(#main-content) > section > *,
    html.hk-anim-ready #product-grid > *,
    html.hk-anim-ready #products-grid > *,
    html.hk-anim-ready #coa-grid > * {
        animation-name: hk-block-in;
        transform: none;
    }
}

/* ---- journal pages ------------------------------------------------------
   The blog template wraps its content in <main> rather than .container or
   <section>, and its card grid is .blog-grid. Same choreography as the rest of
   the site: page block fades, head children rise, cards follow staggered. The
   grid is excluded from the child rise so its cards do not compound with it. */

html.hk-anim body > main:where(:not(#main-content)) { opacity: 0; }

html.hk-anim body > main:where(:not(#main-content)) > *:not(.blog-grid),
html.hk-anim .blog-grid > * {
    opacity: 0;
    transform: translate3d(0, 18px, 0);
}

html.hk-anim .blog-grid { opacity: 0; }

html.hk-anim-ready body > main:where(:not(#main-content)) {
    animation: hk-block-in 240ms ease-out both;
}

html.hk-anim-ready .blog-grid {
    animation: hk-block-in 240ms ease-out both;
    animation-delay: 90ms;
}

html.hk-anim-ready body > main:where(:not(#main-content)) > *:not(.blog-grid) {
    animation: hk-item-rise 460ms cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: 350ms;
}

html.hk-anim-ready body > main:where(:not(#main-content)) > *:nth-child(1):not(.blog-grid) { animation-delay: 0ms; }
html.hk-anim-ready body > main:where(:not(#main-content)) > *:nth-child(2):not(.blog-grid) { animation-delay: 70ms; }
html.hk-anim-ready body > main:where(:not(#main-content)) > *:nth-child(3):not(.blog-grid) { animation-delay: 140ms; }
html.hk-anim-ready body > main:where(:not(#main-content)) > *:nth-child(4):not(.blog-grid) { animation-delay: 210ms; }
html.hk-anim-ready body > main:where(:not(#main-content)) > *:nth-child(5):not(.blog-grid) { animation-delay: 280ms; }

html.hk-anim-ready .blog-grid > * {
    animation: hk-item-rise 440ms cubic-bezier(0.16, 1, 0.3, 1) both;
    animation-delay: 505ms;
}

html.hk-anim-ready .blog-grid > *:nth-child(1) { animation-delay: 120ms; }
html.hk-anim-ready .blog-grid > *:nth-child(2) { animation-delay: 175ms; }
html.hk-anim-ready .blog-grid > *:nth-child(3) { animation-delay: 230ms; }
html.hk-anim-ready .blog-grid > *:nth-child(4) { animation-delay: 285ms; }
html.hk-anim-ready .blog-grid > *:nth-child(5) { animation-delay: 340ms; }
html.hk-anim-ready .blog-grid > *:nth-child(6) { animation-delay: 395ms; }
html.hk-anim-ready .blog-grid > *:nth-child(7) { animation-delay: 450ms; }

html.hk-leaving body > main:where(:not(#main-content)),
html.hk-leaving body > main:where(:not(#main-content)) > *,
html.hk-leaving .blog-grid,
html.hk-leaving .blog-grid > * {
    animation: none;
    opacity: 1;
    transform: none;
}

@media (prefers-reduced-motion: reduce) {
    html.hk-anim body > main:where(:not(#main-content)) > *:not(.blog-grid),
    html.hk-anim .blog-grid > * {
        transform: none;
    }

    html.hk-anim-ready body > main:where(:not(#main-content)) > *:not(.blog-grid),
    html.hk-anim-ready .blog-grid > * {
        animation-name: hk-block-in;
        transform: none;
    }
}
