/* ═══════════════════════════════════════════════════════════════════════
   SWARNIKA JEWELS — effects.css
   Motion only. Every colour, size, font and layout decision lives in
   style.css; nothing here defines a global design token.

   FOUR TECHNIQUES, REUSED EVERYWHERE — nothing else moves on this site:

     1. THE RISE          One scroll entrance. A 18px lift + fade, staggered
                          by --i. Armed only when JS is present, so a
                          scripting-off visitor sees a complete page.
     2. THE VITRINE       The hero carousel. A slow cross-fade between
        CROSS-FADE        .hero-slide elements, with the photograph settling
                          out of a 7% zoom as its slide takes the stage
                          (Ken Burns, earned here: it is a display case
                          turning). The copy block rises in with it.
     3. THE ARCH RESPONSE Product cards, category portals, collection cards
                          and the lookbook answer a pointer with a 4.5%
                          image scale inside the jharokha frame and a 3px
                          shift of the gold key-line. No lift, no shadow —
                          the frame stays put, only what is inside it moves.
     4. THE FLOURISH      The gold rule under a section title spreads open
        OPENING           from its centre once, the diamond arriving last.
                          Only ever armed inside an element the reveal
                          observer controls, so it can never strand itself
                          invisible.

   Plus shared control feedback: arrow nudge on text links, a 1px press on
   buttons, carousel arrows and dots. All transform/opacity.

   RULES HELD:
     · transform and opacity only — nothing here animates width, height,
       padding, margin, colour or a shadow.
     · no will-change anywhere. The two long-running animations promote
       themselves; sprinkling hints on 25 nodes costs more than it buys.
     · no infinite animations. Every keyframe runs once and holds.
     · prefers-reduced-motion: reduce flattens all four techniques — the
       page lands finished, the carousel swaps instantly, no Ken Burns.

   Tokens consumed from style.css: --transition. Everything else motion-
   specific is namespaced --fx-* below.
   ═══════════════════════════════════════════════════════════════════════ */


/* ── Motion-only variables (namespaced, never global design tokens) ──── */
:root {
    --fx-rise:      18px;   /* how far a revealed block travels           */
    --fx-in:        .7s;    /* entrance duration                          */
    --fx-step:      90ms;   /* stagger between siblings                   */
    --fx-hover:     .5s;    /* pointer response on arch media             */
    --fx-fade:      .9s;    /* carousel cross-fade                        */
    --fx-settle:    9s;     /* hero photograph settling out of its zoom   */
    --fx-ease:      cubic-bezier(.4, 0, .2, 1);
    --fx-ease-out:  cubic-bezier(.22, .61, .36, 1);
}


/* ═══ 1 ── THE RISE ══════════════════════════════════════════════════════
   animations.js observes the reveal targets, adds .is-in and sets --i on
   each staggered child. Two contracts are honoured so nothing is stranded:

     [data-reveal]                → .is-in on the element itself
     .stagger-parent              → .is-in on the parent, --i on each
                                    .stagger-child (the markup the four
                                    built pages already emit)

   The resting state is gated on html.has-js, which the inline script in
   <head> sets before first paint. No script, no hiding.
   ════════════════════════════════════════════════════════════════════════ */

html.has-js [data-reveal],
html.has-js .stagger-child {
    --fx-delay: calc(var(--i, 0) * var(--fx-step));
    opacity: 0;
    transform: translate3d(0, var(--fx-rise), 0);
    transition:
        opacity   var(--fx-in) var(--fx-ease-out) var(--fx-delay),
        transform var(--fx-in) var(--fx-ease-out) var(--fx-delay);
}

html.has-js [data-reveal].is-in,
html.has-js .stagger-child.is-in,
html.has-js .stagger-parent.is-in .stagger-child,
html.has-js [data-reveal]:focus-within,
html.has-js .stagger-child:focus-within {
    opacity: 1;
    transform: none;
}


/* ═══ 2 ── THE VITRINE CROSS-FADE ════════════════════════════════════════
   main.js toggles .is-active on one .hero-slide at a time; slide one ships
   with it already set, so the hero is complete on first paint and with
   scripting off. Stacking the slides is style.css's job — this file owns
   only which one is showing and how it arrives.
   ════════════════════════════════════════════════════════════════════════ */

.hero-slide {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition:
        opacity    var(--fx-fade) var(--fx-ease),
        visibility 0s linear var(--fx-fade);
}

.hero-slide.is-active {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    z-index: 1;
    transition:
        opacity    var(--fx-fade) var(--fx-ease),
        visibility 0s linear 0s;
}

/* Clip guard — the photograph is scaled, the frame must not be. */
.hero-photo {
    overflow: hidden;
}

/* The settle. Runs once per activation and holds at its end state, which
   is the element's natural transform — so removing .is-active can never
   snap the picture. */
.hero-slide.is-active .hero-photo img {
    animation: fx-vitrine-settle var(--fx-settle) var(--fx-ease-out) both;
}

@keyframes fx-vitrine-settle {
    from { transform: scale(1.07) translate3d(0, 1.2%, 0); }
    to   { transform: none; }
}

/* The copy arrives just behind the picture. */
.hero-slide.is-active .hero-copy {
    animation: fx-vitrine-copy var(--fx-in) var(--fx-ease-out) 120ms both;
}

@keyframes fx-vitrine-copy {
    from { opacity: 0; transform: translate3d(0, 16px, 0); }
    to   { opacity: 1; transform: none; }
}

/* Carousel controls. */
.hero-arrow,
.hero-dot {
    transition: transform var(--transition), opacity var(--transition);
}

.hero-prev:hover  .ico,
.hero-prev:focus-visible .ico { transform: translate3d(-3px, 0, 0); }
.hero-next:hover  .ico,
.hero-next:focus-visible .ico { transform: translate3d(3px, 0, 0); }

.hero-arrow .ico {
    transition: transform var(--transition);
}

.hero-dot:hover,
.hero-dot:focus-visible { transform: scale(1.3); }


/* ═══ 3 ── THE ARCH RESPONSE ═════════════════════════════════════════════
   One answer to a pointer, used on every browsable piece of media on the
   site. The jharokha frame holds still; the photograph inside it grows
   4.5% and the gold key-line lifts 3px. Deliberately no card lift and no
   shadow — this is a vitrine, the glass does not move.
   ════════════════════════════════════════════════════════════════════════ */

/* Clip guards, so a scaled photograph can never widen its frame. */
.pc-media,
.portal-media,
.col-media,
.look-arch,
.col-row-arch,
.edit-arch {
    overflow: hidden;
}

.pc-media img,
.portal-media img,
.col-media img,
.look-arch img {
    transition: transform var(--fx-hover) var(--fx-ease-out);
}

.arch-key {
    transition:
        transform var(--fx-hover) var(--fx-ease-out),
        opacity   var(--fx-hover) var(--fx-ease-out);
}

.pc:hover          .pc-media img,
.pc:focus-within   .pc-media img,
.portal-link:hover        .portal-media img,
.portal-link:focus-visible .portal-media img,
.col-link:hover           .col-media img,
.col-link:focus-visible   .col-media img,
.look-item:hover          .look-arch img,
.look-item:focus-within   .look-arch img {
    transform: scale(1.045);
}

.pc:hover          .pc-media .arch-key,
.pc:focus-within   .pc-media .arch-key,
.col-link:hover           .col-media .arch-key,
.col-link:focus-visible   .col-media .arch-key,
.look-item:hover          .look-arch .arch-key,
.look-item:focus-within   .look-arch .arch-key {
    transform: translate3d(0, -3px, 0);
    opacity: 1;
}


/* ═══ 4 ── THE FLOURISH OPENING ══════════════════════════════════════════
   flourish() draws two gold rules and a diamond. On reveal the rules
   spread open from the centre and the diamond lands last.

   Armed ONLY inside a reveal target. A flourish sitting in a heading the
   observer does not watch simply renders finished — it can never be left
   invisible waiting for a class that never comes.
   ════════════════════════════════════════════════════════════════════════ */

html.has-js [data-reveal]    .flourish svg,
html.has-js .stagger-child   .flourish svg {
    opacity: 0;
    transform: scaleX(.12);
    transform-origin: 50% 50%;
    transition:
        opacity   var(--fx-in) var(--fx-ease-out) calc(var(--fx-delay, 0ms) + 120ms),
        transform var(--fx-in) var(--fx-ease-out) calc(var(--fx-delay, 0ms) + 120ms);
}

html.has-js [data-reveal]    .fl-eye,
html.has-js .stagger-child   .fl-eye {
    opacity: 0;
    transition: opacity var(--fx-in) var(--fx-ease-out) calc(var(--fx-delay, 0ms) + 380ms);
}

html.has-js [data-reveal].is-in            .flourish svg,
html.has-js .stagger-child.is-in           .flourish svg,
html.has-js .stagger-parent.is-in .stagger-child .flourish svg,
html.has-js [data-reveal]:focus-within     .flourish svg,
html.has-js .stagger-child:focus-within    .flourish svg {
    opacity: 1;
    transform: none;
}

html.has-js [data-reveal].is-in            .fl-eye,
html.has-js .stagger-child.is-in           .fl-eye,
html.has-js .stagger-parent.is-in .stagger-child .fl-eye,
html.has-js [data-reveal]:focus-within     .fl-eye,
html.has-js .stagger-child:focus-within    .fl-eye {
    opacity: 1;
}


/* ═══ SHARED CONTROL FEEDBACK ════════════════════════════════════════════
   Not a fifth technique — the small, sitewide answers a control owes a
   pointer. Transform only, so none of it can fight style.css's colours.
   ════════════════════════════════════════════════════════════════════════ */

.link-arrow {
    transition: transform var(--transition);
}

.text-link:hover         .link-arrow,
.text-link:focus-visible .link-arrow,
.pc-ask:hover            .link-arrow {
    transform: translate3d(4px, 0, 0);
}

.btn,
.chip,
.tool,
.mast-menu,
.drawer-close {
    transition: transform var(--transition);
}

.btn:active,
.chip:active,
.tool:active,
.mast-menu:active,
.drawer-close:active {
    transform: translate3d(0, 1px, 0);
}

/* Nav caret answers its own menu opening. */
.nav-caret {
    transition: transform var(--transition);
}

.nav-has-menu:hover        .nav-caret,
.nav-has-menu:focus-within .nav-caret {
    transform: rotate(90deg);
}

/* The wishlist / enquiry drawer. No class contract was agreed with the JS
   agent, so this leans on @starting-style: the panel eases in the first
   time it is rendered (i.e. when [hidden] is removed) and simply appears
   where the browser does not support it. Nothing is hidden by this file,
   so a different open-class in main.js cannot strand the drawer. */
.drawer-panel {
    transition: transform var(--fx-in) var(--fx-ease-out);
}

.drawer-scrim {
    transition: opacity var(--fx-in) var(--fx-ease);
}

@starting-style {
    .drawer:not([hidden]) .drawer-panel { transform: translate3d(100%, 0, 0); }
    .drawer:not([hidden]) .drawer-scrim { opacity: 0; }
}


/* ═══ REDUCED MOTION — everything lands finished ═════════════════════════
   The blanket kills durations; the explicit rules below undo the resting
   states, because a 0.001ms transition on an element that is still waiting
   for .is-in would leave it invisible. main.js owns stopping the carousel
   timer; this file makes the swap itself instant.
   ════════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {

    *,
    *::before,
    *::after {
        animation-duration: .001ms !important;
        animation-delay: 0s !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        transition-delay: 0s !important;
        scroll-behavior: auto !important;
    }

    /* 1 + 4 — the page arrives already revealed. */
    html.has-js [data-reveal],
    html.has-js .stagger-child,
    html.has-js [data-reveal]  .flourish svg,
    html.has-js .stagger-child .flourish svg,
    html.has-js [data-reveal]  .fl-eye,
    html.has-js .stagger-child .fl-eye {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }

    /* 2 — instant slide swap, no settle, no copy entrance. */
    .hero-slide,
    .hero-slide.is-active {
        transition: none !important;
    }

    .hero-slide.is-active .hero-photo img,
    .hero-slide.is-active .hero-copy {
        animation: none !important;
        transform: none !important;
    }

    /* 3 + controls — the frame answers with nothing but the pointer. */
    .pc-media img,
    .portal-media img,
    .col-media img,
    .look-arch img,
    .arch-key,
    .link-arrow,
    .nav-caret,
    .hero-arrow .ico,
    .hero-dot,
    .btn,
    .chip,
    .tool,
    .mast-menu,
    .drawer-close,
    .drawer-panel,
    .drawer-scrim {
        transition: none !important;
    }

    .pc:hover          .pc-media img,
    .pc:focus-within   .pc-media img,
    .portal-link:hover        .portal-media img,
    .portal-link:focus-visible .portal-media img,
    .col-link:hover           .col-media img,
    .col-link:focus-visible   .col-media img,
    .look-item:hover          .look-arch img,
    .look-item:focus-within   .look-arch img,
    .hero-dot:hover,
    .hero-dot:focus-visible,
    .hero-prev:hover  .ico,
    .hero-prev:focus-visible .ico,
    .hero-next:hover  .ico,
    .hero-next:focus-visible .ico,
    .text-link:hover         .link-arrow,
    .text-link:focus-visible .link-arrow,
    .pc-ask:hover            .link-arrow,
    .nav-has-menu:hover        .nav-caret,
    .nav-has-menu:focus-within .nav-caret,
    .btn:active,
    .chip:active,
    .tool:active,
    .mast-menu:active,
    .drawer-close:active {
        transform: none !important;
    }

    .pc:hover          .pc-media .arch-key,
    .pc:focus-within   .pc-media .arch-key,
    .col-link:hover           .col-media .arch-key,
    .col-link:focus-visible   .col-media .arch-key,
    .look-item:hover          .look-arch .arch-key,
    .look-item:focus-within   .look-arch .arch-key {
        transform: none !important;
    }
}
