/* ==========================================================================
   KAVITA TRADERS — motion & conversion layer
   Loaded after style.css. Everything here degrades to "no animation, still
   perfectly usable" when prefers-reduced-motion is set.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. PAGE INTRO — a brief gold curtain with the brand mark
   -------------------------------------------------------------------------- */
.intro{
  position:fixed;inset:0;z-index:200;display:grid;place-items:center;
  background:var(--ink);
  transition:opacity .7s var(--ease-out),visibility .7s;
}
.intro .im{
  width:64px;height:64px;display:grid;place-items:center;border-radius:50%;
  border:1px solid rgba(200,178,108,.45);
  font-family:"Playfair Display",serif;font-size:1.7rem;color:var(--gold-lt);
  opacity:0;transform:scale(.9);
  animation:introMark 1.15s var(--ease-out) forwards;
}
.intro .il{
  position:absolute;left:50%;bottom:38%;transform:translateX(-50%);
  width:0;height:1px;background:var(--gold-rule);
  animation:introLine 1.15s var(--ease-out) .18s forwards;
}
@keyframes introMark{to{opacity:1;transform:scale(1)}}
@keyframes introLine{to{width:132px}}
.intro.done{opacity:0;visibility:hidden;pointer-events:none}
html.intro-lock,html.intro-lock body{overflow:hidden}

/* --------------------------------------------------------------------------
   2. SPLIT-WORD HEADLINE REVEAL
   -------------------------------------------------------------------------- */
.w{display:inline-block;overflow:hidden;vertical-align:top;padding-bottom:.1em;margin-bottom:-.1em}
.wi{
  display:inline-block;transform:translateY(110%);opacity:0;
  transition:transform 1.05s var(--ease-out),opacity .8s var(--ease-out);
  will-change:transform;
}
.in .wi{transform:translateY(0);opacity:1}

/* --------------------------------------------------------------------------
   3. DIRECTIONAL / STAGGERED REVEALS
   -------------------------------------------------------------------------- */
.rv{opacity:0;transition:opacity 1s var(--ease-out),transform 1s var(--ease-out);will-change:transform,opacity}
.rv-up   {transform:translateY(34px)}
.rv-left {transform:translateX(-34px)}
.rv-right{transform:translateX(34px)}
.rv-fade {transform:none}
.rv-scale{transform:scale(.96)}
.rv.in{opacity:1;transform:none}

/* children stagger — set by JS as --i */
.stagger > *{opacity:0;transform:translateY(26px);transition:opacity .85s var(--ease-out),transform .85s var(--ease-out);transition-delay:calc(var(--i,0) * 85ms)}
.stagger.in > *{opacity:1;transform:none}

/* --------------------------------------------------------------------------
   4. IMAGE CURTAIN REVEAL — a gold sheet slides off the image
   -------------------------------------------------------------------------- */
.curtain{position:relative;overflow:hidden}
.curtain::after{
  content:"";position:absolute;inset:0;z-index:4;pointer-events:none;
  background:linear-gradient(115deg,var(--ink) 0%,var(--ink-2) 55%,var(--gold-dp) 140%);
  transform:translateX(0);
  transition:transform 1.25s cubic-bezier(.76,0,.24,1);
}
.curtain.in::after{transform:translateX(101%)}
.curtain img,.curtain video{transform:scale(1.14);transition:transform 1.7s var(--ease-out)}
.curtain.in img,.curtain.in video{transform:scale(1)}

/* --------------------------------------------------------------------------
   5. PARALLAX
   -------------------------------------------------------------------------- */
.px{will-change:transform}

/* --------------------------------------------------------------------------
   6. MAGNETIC BUTTONS + CUSTOM CURSOR (fine pointers only)
   -------------------------------------------------------------------------- */
.mag{will-change:transform}

@media (hover:hover) and (pointer:fine){
  .kcur{
    position:fixed;top:0;left:0;z-index:190;pointer-events:none;
    width:9px;height:9px;border-radius:50%;background:var(--gold);
    transform:translate3d(-50%,-50%,0);
    transition:width .35s var(--ease),height .35s var(--ease),background .35s var(--ease),opacity .3s;
    mix-blend-mode:difference;opacity:0;
  }
  .kcur.on{opacity:1}
  .kcur.lg{width:46px;height:46px;background:rgba(200,178,108,.55)}
  .kcur-ring{
    position:fixed;top:0;left:0;z-index:189;pointer-events:none;
    width:34px;height:34px;border-radius:50%;border:1px solid rgba(200,178,108,.5);
    transform:translate3d(-50%,-50%,0);opacity:0;transition:opacity .35s,width .35s var(--ease),height .35s var(--ease);
  }
  .kcur-ring.on{opacity:1}
  .kcur-ring.lg{width:0;height:0;opacity:0}
}

/* --------------------------------------------------------------------------
   7. HERO VIDEO
   -------------------------------------------------------------------------- */
.hero-media .frame video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.hero-media .frame{background:var(--ink-2)}

/* the hero video is shot vertical, so the frame goes portrait to match it */
.hero-media .frame{aspect-ratio:4/5}

/* video sitting in a normal content block — must reserve its own height */
.fimg video{display:block;width:100%;height:auto;aspect-ratio:16/9;object-fit:cover;background:var(--ink-2)}
.fimg-tall video{aspect-ratio:3/4}
.fimg video img{width:100%;height:100%;object-fit:cover}
/* if the video can't play we swap in the poster as a plain image */
.fimg .vfallback{display:block;width:100%}
.vid-wrap{position:relative;overflow:hidden;border-radius:var(--r)}
.vid-wrap video{width:100%;height:100%;object-fit:cover;display:block}

/* full-bleed video band */
.vband{position:relative;overflow:hidden;isolation:isolate;background:var(--ink)}
.vband video{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;
  opacity:.34;filter:saturate(.85) contrast(.92);
}
.vband::after{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(to right,rgba(20,20,16,.92) 0%,rgba(20,20,16,.72) 46%,rgba(20,20,16,.55) 100%),
    radial-gradient(80% 70% at 88% 20%,rgba(200,178,108,.20),transparent 62%);
}
.vband .inner{position:relative;z-index:2}

/* the shade wall carries the book footage behind it, but the book's own
   lettering fights the headline — hold it well back */
.shadewall.vband video{opacity:.16;filter:saturate(.7) blur(1px)}
.shadewall.vband::after{
  background:
    linear-gradient(to bottom,rgba(30,30,24,.90),rgba(30,30,24,.80) 45%,rgba(30,30,24,.90)),
    radial-gradient(70% 60% at 82% 8%,rgba(200,178,108,.16),transparent 62%);
}

/* --------------------------------------------------------------------------
   8. GRAIN — the thing that quietly makes flat colour look expensive
   -------------------------------------------------------------------------- */
.grain::before{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;opacity:.30;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   9. COUNTERS
   -------------------------------------------------------------------------- */
.hero-stats b{font-variant-numeric:tabular-nums}

/* --------------------------------------------------------------------------
   10. GOLD SHEEN sweep across the signature word
   -------------------------------------------------------------------------- */
.sheen{
  background:linear-gradient(100deg,var(--gold-dp) 12%,var(--gold-lt) 34%,#F6EED6 46%,var(--gold-lt) 58%,var(--gold-dp) 82%);
  background-size:220% 100%;
  -webkit-background-clip:text;background-clip:text;color:transparent;
  animation:sheen 7s ease-in-out infinite;
}
@keyframes sheen{0%,100%{background-position:130% 0}50%{background-position:-30% 0}}

/* --------------------------------------------------------------------------
   11. CARD POLISH
   -------------------------------------------------------------------------- */
.card .media{transition:transform .7s var(--ease-out),box-shadow .7s var(--ease-out)}
.card:hover .media{transform:translateY(-6px);box-shadow:var(--sh-md)}
.card .pname{background-image:linear-gradient(var(--gold),var(--gold));background-size:0 1px;background-repeat:no-repeat;background-position:0 100%;transition:background-size .5s var(--ease-out)}
.card:hover .pname{background-size:100% 1px}

.cat{transition:box-shadow .7s var(--ease-out)}
.cat:hover{box-shadow:var(--sh-md)}

/* --------------------------------------------------------------------------
   12. WHATSAPP CONVERSION LAYER
   -------------------------------------------------------------------------- */

/* 12a — floating button that expands into a label on desktop */
.wa-float{overflow:hidden;width:58px;transition:width .5s var(--ease-out),transform .45s var(--ease),box-shadow .45s var(--ease);white-space:nowrap;justify-content:flex-start;padding-left:15px;display:flex;align-items:center;gap:.7rem}
.wa-float .wl{
  font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;font-weight:500;color:#fff;
  opacity:0;transition:opacity .3s var(--ease);
}
@media (hover:hover) and (pointer:fine){
  .wa-float:hover{width:210px;border-radius:32px}
  .wa-float:hover .wl{opacity:1;transition-delay:.12s}
}

/* 12b — sticky mobile action bar: the single biggest conversion lever */
.mbar{
  position:fixed;left:0;right:0;bottom:0;z-index:88;display:none;
  gap:0;background:rgba(248,247,242,.96);backdrop-filter:blur(16px);
  border-top:1px solid var(--line);
  padding-bottom:env(safe-area-inset-bottom,0);
  transform:translateY(102%);transition:transform .55s var(--ease-out);
  box-shadow:0 -8px 30px rgba(35,35,28,.10);
}
.mbar.up{transform:translateY(0)}
.mbar a,.mbar button{
  flex:1;display:flex;align-items:center;justify-content:center;gap:.5rem;
  padding:1.05rem .6rem;font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;font-weight:500;
  color:var(--ink);position:relative;
}
.mbar .m-wa{background:var(--wa-dp);color:#fff}
.mbar .m-enq .mb-badge{
  min-width:18px;height:18px;padding:0 5px;border-radius:999px;background:var(--ink);color:var(--gold-lt);
  font-size:.58rem;display:grid;place-items:center;
}
@media (max-width:860px){
  .mbar{display:flex}
  .wa-float{display:none}
  body{padding-bottom:56px}
  .toast-wrap{bottom:76px}
}

/* 12c — scroll-triggered enquiry nudge */
.nudge{
  position:fixed;right:22px;bottom:96px;z-index:86;width:min(90vw,326px);
  background:var(--porcelain);border:1px solid var(--line);border-left:2px solid var(--gold);
  border-radius:var(--r);box-shadow:var(--sh-lg);padding:1.3rem 1.4rem 1.4rem;
  opacity:0;transform:translateY(18px) scale(.97);visibility:hidden;
  transition:opacity .55s var(--ease-out),transform .55s var(--ease-out),visibility .55s;
}
.nudge.show{opacity:1;transform:none;visibility:visible}
.nudge .nx{position:absolute;top:8px;right:10px;width:28px;height:28px;display:grid;place-items:center;color:var(--taupe);font-size:1.1rem;line-height:1}
.nudge .nx:hover{color:var(--ink)}
.nudge .ne{font-size:.58rem;letter-spacing:.26em;text-transform:uppercase;color:var(--gold-dp);display:block;margin-bottom:.6rem}
.nudge h4{font-family:"Playfair Display",serif;font-size:1.35rem;font-weight:400;color:var(--ink);margin:0 0 .5rem;line-height:1.2}
.nudge p{font-size:.83rem;color:var(--taupe);margin:0 0 1.1rem;line-height:1.6}
@media (max-width:860px){.nudge{right:12px;left:12px;bottom:74px;width:auto}}

/* 12d — "ask rate on whatsapp" link inside product cards */
.card .askwa{
  display:inline-flex;align-items:center;gap:.45em;margin-top:.7rem;
  font-size:.6rem;letter-spacing:.17em;text-transform:uppercase;color:var(--wa-dp);
  opacity:.85;transition:opacity .3s,gap .3s var(--ease);
}
.card .askwa:hover{opacity:1;gap:.7em}
.card .askwa svg{flex-shrink:0}

/* the trade price slot, upgraded in place into the WhatsApp link */
.card .askwa-inline{
  display:inline-flex;align-items:center;gap:.45em;margin-top:auto;padding-top:.35rem;
  font-size:.66rem;letter-spacing:.18em;text-transform:uppercase;color:var(--wa-dp);
  transition:gap .3s var(--ease),color .3s;
}
.card .askwa-inline:hover{gap:.7em;color:#0E5544}
.card .askwa-inline svg{flex-shrink:0}

/* --------------------------------------------------------------------------
   14. THE SHADE WALL
   -------------------------------------------------------------------------- */
.shadewall .shead{align-items:flex-end}
.sw-readout{display:flex;align-items:center;gap:1rem;flex-shrink:0}
.sw-chip{
  width:62px;height:62px;border-radius:50%;flex-shrink:0;
  background:#EFBAA3;border:1px solid rgba(255,255,255,.22);
  box-shadow:0 8px 26px rgba(0,0,0,.34);
  transition:background .45s var(--ease),transform .45s var(--ease);
}
.sw-readout.pop .sw-chip{transform:scale(1.09)}
.sw-meta{display:flex;flex-direction:column;gap:.28rem}
.sw-meta b{font-family:"Playfair Display",serif;font-size:1.5rem;font-weight:400;color:#FAF9F3;line-height:1}
.sw-meta small{font-size:.6rem;letter-spacing:.22em;text-transform:uppercase;color:var(--gold-lt)}

.sw-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(78px,1fr));
  gap:clamp(8px,1vw,14px);margin-top:.6rem;
}
.sw{
  position:relative;aspect-ratio:1/1.32;border-radius:60px 60px 8px 8px;
  border:0;padding:0;cursor:pointer;overflow:hidden;
  box-shadow:inset 0 -18px 26px rgba(0,0,0,.14),0 5px 16px rgba(0,0,0,.24);
  opacity:0;transform:translateY(18px) scale(.94);
  transition:opacity .6s var(--ease-out),transform .6s var(--ease-out),box-shadow .4s var(--ease);
  transition-delay:calc(var(--i,0) * 26ms);
}
.sw::after{
  content:"";position:absolute;left:16%;top:8%;width:26%;height:44%;
  border-radius:50%;background:linear-gradient(180deg,rgba(255,255,255,.5),transparent);
  pointer-events:none;
}
.sw-grid.in .sw{opacity:1;transform:none}
.sw:hover,.sw:focus-visible{transform:translateY(-7px) scale(1.05);box-shadow:inset 0 -18px 26px rgba(0,0,0,.14),0 16px 34px rgba(0,0,0,.4);outline:none;z-index:2}
.sw i{
  position:absolute;left:0;right:0;bottom:5px;text-align:center;font-style:normal;
  font-size:.56rem;letter-spacing:.12em;color:rgba(255,255,255,.9);
  text-shadow:0 1px 3px rgba(0,0,0,.6);opacity:0;transition:opacity .3s;
}
.sw:hover i,.sw:focus-visible i{opacity:1}
.sw.dark i{color:rgba(255,255,255,.95)}
.sw.light i{color:rgba(20,20,16,.75);text-shadow:0 1px 2px rgba(255,255,255,.5)}
.sw-note{margin-top:2rem;font-size:.76rem;color:rgba(232,230,218,.55);letter-spacing:.04em}
.sw-note b{color:var(--gold-lt);font-weight:500}

@media (max-width:620px){
  .shadewall .shead{align-items:flex-start}
  .sw-grid{grid-template-columns:repeat(auto-fill,minmax(56px,1fr))}
  .sw-chip{width:50px;height:50px}
}

/* --------------------------------------------------------------------------
   15. SCROLL-DRIVEN HORIZONTAL PRODUCT GALLERY
   -------------------------------------------------------------------------- */
.scroller{position:relative;background:var(--porcelain)}
.sc-sticky{position:sticky;top:0;height:100vh;display:flex;flex-direction:column;justify-content:center;overflow:hidden}
.sc-head{
  display:flex;align-items:flex-end;justify-content:space-between;gap:2rem;flex-wrap:wrap;
  margin-bottom:clamp(1.5rem,3vw,2.6rem);width:100%;
}
.sc-head .st{max-width:60ch}
.sc-head h2{margin-top:.9rem}
.sc-right{display:flex;flex-direction:column;align-items:flex-end;gap:1.1rem}
.sc-progress{width:min(230px,34vw);height:1px;background:var(--line);position:relative;overflow:hidden}
.sc-progress i{position:absolute;inset:0;transform-origin:left;transform:scaleX(0);background:var(--gold-grad);display:block}
.sc-track{
  display:flex;gap:clamp(16px,2vw,28px);
  padding-inline:var(--gutter);
  will-change:transform;
}
.sc-track .card{width:clamp(230px,23vw,300px);flex-shrink:0}
.sc-track .card .media{aspect-ratio:4/5}
/* the scroller needs real page height to scrub against — set by JS */
.sc-fallback{display:none}

@media (max-width:900px),(prefers-reduced-motion:reduce){
  .scroller{display:none}
  .sc-fallback{display:block}
}

/* --------------------------------------------------------------------------
   17. CATEGORY TILE HOVER VIDEO
   -------------------------------------------------------------------------- */
.cat .catv{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:1;
  opacity:0;transition:opacity .65s var(--ease);
}
.cat:hover .catv,.cat:focus-visible .catv{opacity:1}
.cat .veil{z-index:2}
.cat .cnum,.cat .cap{z-index:3}
/* a tiny "plays on hover" hint so the video is discoverable */
.cat:has(.catv) .cnum::after{content:" ▸";color:var(--gold-lt);opacity:.8}
/* Touch has no hover, so scroll drives these instead (motion.js adds .vplay
   while the tile is on screen). They used to be display:none here, which meant
   the whole tile-video layer was missing on mobile. */
@media (hover:none){
  .cat .catv{opacity:0;transition:opacity .8s var(--ease-out)}
  .cat.vplay .catv{opacity:1}
  .cat:has(.catv) .cnum::after{content:""}
}

/* --------------------------------------------------------------------------
   26. SCROLL-SCRUBBED VIDEO
   The frame is bound to scroll position by motion.js. Until the metadata
   loads, and on reduced-motion or a metered connection, the poster underneath
   is what shows — so this can only ever add, never break the layout.
   -------------------------------------------------------------------------- */
.scrubwrap{position:relative;overflow:hidden;border-radius:var(--r);background:var(--ink-2);isolation:isolate}
.scrubwrap img{display:block;width:100%;height:auto}
.scrubwrap video{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .9s var(--ease-out);
}
.scrubwrap.ready video{opacity:1}
.scrubwrap.static video{display:none}
/* a soft vignette so the book sits into the page rather than on top of it */
.scrubwrap::after{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:2;
  background:radial-gradient(78% 62% at 50% 42%,transparent 55%,rgba(30,30,24,.30));
}
.scrubhint{
  position:absolute;left:50%;bottom:1.1rem;transform:translateX(-50%);z-index:3;
  font-size:.55rem;letter-spacing:.26em;text-transform:uppercase;
  color:rgba(248,247,242,.72);pointer-events:none;
  display:flex;align-items:center;gap:.5em;
}
.scrubhint i{display:block;width:16px;height:1px;background:rgba(226,211,160,.6)}
.scrubwrap.static .scrubhint{display:none}
@media (prefers-reduced-motion:reduce){.scrubwrap video{display:none}.scrubhint{display:none}}

/* --------------------------------------------------------------------------
   18. REEL STRIP
   -------------------------------------------------------------------------- */
.reel-strip{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(12px,2vw,26px)}
@media (max-width:1100px){.reel-strip{grid-template-columns:repeat(3,1fr)}.reel-strip .reel:nth-child(4){display:none}}
.reel{margin:0;position:relative;border-radius:var(--r);overflow:hidden;background:var(--ink-2)}
.reel video{display:block;width:100%;aspect-ratio:9/16;object-fit:cover;background:var(--ink-2)}
.reel::after{content:"";position:absolute;inset:0;pointer-events:none;border:1px solid rgba(226,211,160,.20);z-index:2}
.reel figcaption{
  position:absolute;left:0;right:0;bottom:0;z-index:3;padding:2.4rem 1.1rem 1.05rem;
  font-size:.62rem;letter-spacing:.17em;text-transform:uppercase;color:rgba(255,255,255,.9);
  background:linear-gradient(to top,rgba(20,20,16,.86),transparent);
}
.reel .vfallback{width:100%;aspect-ratio:9/16;object-fit:cover}
@media (max-width:720px){
  .reel-strip{grid-template-columns:1fr 1fr;gap:10px}
  .reel:last-child{display:none}
  .reel figcaption{font-size:.55rem;padding:1.8rem .7rem .8rem}
}

/* --------------------------------------------------------------------------
   16. SCROLL PROGRESS BAR
   -------------------------------------------------------------------------- */
.kprog{position:fixed;top:0;left:0;right:0;height:2px;z-index:100;background:transparent;pointer-events:none}
.kprog i{display:block;height:100%;width:100%;transform-origin:left;transform:scaleX(0);background:var(--gold-grad)}

/* --------------------------------------------------------------------------
   19. QA FIXES
   -------------------------------------------------------------------------- */

/* Tile index numbers. A text-shadow alone measured 1.78:1 against pale photos —
   nowhere near the 4.5:1 needed at this size. Give the number its own scrim so
   contrast is guaranteed regardless of what is behind it. */
.cat .cnum{
  background:rgba(22,22,17,.8);   /* .62 measured only 3.56:1 over a pale photo */
  padding:.42em .62em;border-radius:2px;
  backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);
  color:var(--gold-lt);line-height:1;
}
.cat .cap h3,.cat .cap span{text-shadow:0 1px 8px rgba(0,0,0,.6)}

/* contact cards overran a 390px viewport by 78px — `overflow-x:clip` was hiding
   it, so the Instagram handle (the page's main CTA) was cut mid-word */
.ccards,.ccard,.ccard > div{min-width:0}
.ccard .big,.ccard p,.ccard a{overflow-wrap:anywhere}
@media (max-width:520px){
  .ccard{gap:.9rem;padding:1.25rem}
  .ccard .big{font-size:1.12rem}
}

/* cards stretched to the tallest in the row, opening up to 200px of dead space
   under short ones. Let each card be its own height instead. */
.pgrid,.prail,.sc-track{align-items:start}

/* the filter row scrolls but gave no hint that it did */
.filters{
  -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 46px),transparent);
  mask-image:linear-gradient(to right,#000 calc(100% - 46px),transparent);
}

/* shade numbers are the whole point of the section — always show them */
.sw i{opacity:.85}
.sw:hover i,.sw:focus-visible i{opacity:1}

/* --- tap targets & minimum legible type (mobile) --- */
.card .askwa,.card .askwa-inline{padding-block:.5rem;margin-top:.35rem}
.tlink{padding-block:.55em .5em}
.footer li a{padding-block:.3rem}
.crumbs a{padding-block:.35rem}

@media (max-width:720px){
  .pill{font-size:.62rem}
  .card .blabel{font-size:.62rem}
  .card .save{font-size:.66rem}
  .btn-sm{font-size:.66rem}
  .footer h4{font-size:.7rem}
  .hero-stats small{font-size:.63rem}
  .card .askwa,.card .askwa-inline{font-size:.64rem;padding-block:.62rem}
  .sortsel{padding-block:.7em}

  /* four stats wrapped 3 + 1, orphaning "Pan-India" */
  .hero-stats{display:grid;grid-template-columns:1fr 1fr;gap:1.3rem 1.6rem}

  /* seven 3:4 tiles made the category section ~4000px of scrolling */
  .cat,.cat.tall{aspect-ratio:4/3}
  .cat.wide{aspect-ratio:16/9}
}

/* --------------------------------------------------------------------------
   20. NATIVE SCROLL-DRIVEN ANIMATION  (progressive enhancement)
   Chrome/Edge 115+, Firefox 132+, Safari 18+. These run on the compositor,
   so they stay glued to the scroll with zero main-thread work. Browsers
   without support simply skip the whole block and keep the JS reveals.
   Nothing essential lives in here — it is all polish on top.
   -------------------------------------------------------------------------- */
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){

    /* hero drifts up gently as you leave it */
    .hero-media{
      animation:heroDrift linear both;
      animation-timeline:view();
      animation-range:exit-crossing 0% exit 100%;
    }
    @keyframes heroDrift{to{transform:translateY(-46px)}}

    /* the page heading softens and lifts as it scrolls away */
    .page-head h1,.hero h1{
      animation:headOut linear both;
      animation-timeline:view();
      animation-range:exit 10% exit 100%;
    }
    @keyframes headOut{to{opacity:.25;transform:translateY(-26px)}}

    /* instagram tiles breathe */
    .iggrid a img{
      animation:tileBreathe linear both;
      animation-timeline:view();
      animation-range:entry 0% exit 100%;
    }
    @keyframes tileBreathe{from{transform:scale(1.14)}to{transform:scale(1)}}

    /* reels drift at different rates — cheap, convincing depth */
    .reel-strip .reel:nth-child(odd) video{animation:reelA linear both;animation-timeline:view();animation-range:entry 0% exit 100%}
    .reel-strip .reel:nth-child(even) video{animation:reelB linear both;animation-timeline:view();animation-range:entry 0% exit 100%}
    @keyframes reelA{from{transform:translateY(3.5%) scale(1.09)}to{transform:translateY(-3.5%) scale(1.09)}}
    @keyframes reelB{from{transform:translateY(-3.5%) scale(1.09)}to{transform:translateY(3.5%) scale(1.09)}}

    /* the eyebrow rule draws itself in */
    .eyebrow::before{
      animation:ruleDraw linear both;
      animation-timeline:view();
      animation-range:entry 10% entry 90%;
    }
    @keyframes ruleDraw{from{width:0;opacity:0}to{width:26px;opacity:.7}}

    /* section headings rise a touch on approach */
    .shead h2{
      animation:headIn linear both;
      animation-timeline:view();
      animation-range:entry 0% entry 85%;
    }
    @keyframes headIn{from{transform:translateY(22px)}to{transform:translateY(0)}}
  }
}

/* --------------------------------------------------------------------------
   21. HERO SCROLL CUE
   -------------------------------------------------------------------------- */
.scrollcue{
  display:inline-flex;align-items:center;gap:.7rem;margin-top:2.4rem;
  font-size:.58rem;letter-spacing:.26em;text-transform:uppercase;
  color:rgba(237,235,224,.55);
}
.scrollcue i{
  position:relative;display:block;width:1px;height:34px;background:rgba(226,211,160,.28);overflow:hidden;
}
.scrollcue i::after{
  content:"";position:absolute;left:0;top:0;width:1px;height:12px;background:var(--gold-lt);
  animation:cueRun 2.4s var(--ease-out) infinite;
}
@keyframes cueRun{0%{transform:translateY(-14px)}60%,100%{transform:translateY(34px)}}
@media (max-width:1080px){.scrollcue{display:none}}


/* --------------------------------------------------------------------------
   22. MOBILE MOTION + CONVERSION TUNING
   Desktop timings feel slow on a phone: the thumb moves faster than the
   viewport, so long staggers read as "nothing is loading". Everything below
   shortens the distance and the delay without removing the motion.
   -------------------------------------------------------------------------- */
@media (max-width:860px){
  /* shorter travel + faster settle */
  .rv{transition-duration:.55s}
  .rv-up{transform:translateY(20px)}
  .rv-left,.rv-right{transform:translateY(20px)}
  .stagger > *{transition-duration:.5s;transform:translateY(16px)}
  /* cap the stagger so the 8th card isn't half a second behind the 1st */
  .stagger > *{transition-delay:calc(min(var(--i,0),4) * 45ms)}
  .wi{transition-duration:.6s}
  .curtain::after{transition-duration:.8s}
  .curtain img,.curtain video{transition-duration:1s}
  .sw{transition-duration:.42s;transition-delay:calc(min(var(--i,0),12) * 14ms)}

  /* the intro curtain is pure cost on a phone — get to content sooner */
  .intro .im{animation-duration:.75s}
  .intro .il{animation-duration:.75s}

  /* tap feedback: phones have no hover, so presses need to feel acknowledged */
  .btn:active{transform:scale(.975)}
  .card:active .media{transform:scale(.99)}
  .sw:active{transform:translateY(-4px) scale(1.06)}
  .mbar a:active,.mbar button:active{filter:brightness(.92)}
  .cat:active{transform:scale(.995)}
}

/* the sticky bar is the primary conversion surface on mobile — make the
   WhatsApp half unmistakably the primary action */
@media (max-width:860px){
  .mbar .m-wa{font-weight:600;letter-spacing:.14em}
  .mbar .m-wa svg{width:19px;height:19px}
}

/* --------------------------------------------------------------------------
   23. BRAND FILTER ROW + STOCK-DEPTH SIGNALS
   -------------------------------------------------------------------------- */
.filters-brand{padding-top:0;padding-bottom:.9rem;gap:.42rem}
.filters-brand .chip{
  font-size:.6rem;padding:.5em 1.05em;
  border-color:var(--line-gold);color:var(--gold-dp);
}
.filters-brand .chip:hover{border-color:var(--gold);color:var(--ink)}
.filters-brand .chip.active{background:var(--gold-dp);border-color:var(--gold-dp);color:#fff}
.filters-brand .chip i{font-style:normal;opacity:.62;font-size:.92em}
.filters-brand .chip-limited{opacity:.86}

/* stock-depth badge on cards the client flagged as partial stock */
.pill-limited{background:var(--porcelain);color:var(--rose);border:1px solid rgba(156,95,74,.35)}

/* --------------------------------------------------------------------------
   24. BRAND WALL
   -------------------------------------------------------------------------- */
.brandgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(10px,1.4vw,18px)}
.bcard{
  position:relative;display:flex;flex-direction:column;gap:.5rem;
  padding:1.5rem 1.4rem 1.25rem;border:1px solid var(--line);border-radius:var(--r);
  background:var(--porcelain-2);overflow:hidden;
  transition:border-color .45s var(--ease),transform .45s var(--ease),box-shadow .45s var(--ease);
}
.bcard::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:2px;
  background:var(--gold-grad);transform:scaleX(0);transform-origin:left;
  transition:transform .5s var(--ease-out);
}
.bcard:hover{border-color:var(--line-gold);transform:translateY(-4px);box-shadow:var(--sh-sm)}
.bcard:hover::after{transform:scaleX(1)}
.bname{font-family:"Playfair Display",serif;font-size:1.42rem;color:var(--ink);line-height:1.1}
.bnote{font-size:.8rem;color:var(--taupe);line-height:1.5}
.bfoot{display:flex;align-items:center;justify-content:space-between;gap:.6rem;margin-top:auto;padding-top:.7rem}
.bcount{font-size:.58rem;letter-spacing:.2em;text-transform:uppercase;color:var(--gold-dp)}
.btag{
  font-size:.55rem;letter-spacing:.16em;text-transform:uppercase;
  padding:.32em .6em;border-radius:var(--r);
  background:rgba(156,95,74,.1);color:var(--rose);border:1px solid rgba(156,95,74,.3);
}
.bcard-limited{background:var(--porcelain)}
@media (max-width:860px){.brandgrid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:460px){.brandgrid{grid-template-columns:1fr}}

/* --------------------------------------------------------------------------
   24b. RATED ON AMAZON — real ratings, scrolled horizontally
   Every card is a live listing. Rendered by renderRatingWall() in main.js and
   the section stays `hidden` unless there is genuine rating data to show, so
   this can never render an empty or invented claim.
   -------------------------------------------------------------------------- */
/* The wall drifts on its own, using the same `marq` keyframe as the
   announcement bar so the motion matches the rest of the site. main.js prints
   the cards twice into .ratetrack, so translateX(-50%) lands exactly on the
   start of the copy and the loop is seamless.

   It pauses on hover, on keyboard focus, and while a finger is on it — a strip
   that keeps moving while you are trying to read or tap a card is the classic
   way this effect turns into an irritation. */
.ratewall{
  overflow:hidden;padding-bottom:.6rem;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 5%,#000 95%,transparent 100%);
          mask-image:linear-gradient(90deg,transparent 0,#000 5%,#000 95%,transparent 100%);
}
.ratetrack{
  display:flex;width:max-content;gap:clamp(10px,1.3vw,16px);
  animation:marq 64s linear infinite;
  will-change:transform;
}
.ratewall:hover .ratetrack,
.ratewall:focus-within .ratetrack,
.ratewall.held .ratetrack{animation-play-state:paused}
@media (prefers-reduced-motion:reduce){
  .ratetrack{animation:none}
  .ratewall{overflow-x:auto;scrollbar-width:none}
}
.ratecard{
  flex:0 0 clamp(190px,22vw,230px);
  display:flex;flex-direction:column;
  border:1px solid var(--line);border-radius:var(--r);overflow:hidden;
  background:var(--porcelain-2);
  transition:border-color .5s var(--ease),transform .5s var(--ease-out),box-shadow .5s var(--ease-out);
}
.ratecard img{width:100%;aspect-ratio:1;object-fit:cover;display:block;background:var(--porcelain)}
.ratebody{display:flex;flex-direction:column;gap:.34rem;padding:.95rem 1rem 1.05rem}
.ratecard .stars{display:flex;align-items:center;gap:.45em;font-size:.72rem;color:var(--taupe)}
.ratecard .stars b{color:var(--gold-dp);letter-spacing:.06em;font-weight:400}
.ratename{
  font-family:"Playfair Display",serif;font-size:.95rem;line-height:1.25;color:var(--ink);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.ratecount{font-size:.56rem;letter-spacing:.18em;text-transform:uppercase;color:var(--gold-dp);margin-top:auto;padding-top:.3rem}
@media (hover:hover){
  .ratecard:hover{border-color:var(--line-gold);transform:translateY(-5px);box-shadow:var(--sh-sm)}
}
@media (max-width:640px){ .ratecard{flex-basis:64vw} }

/* --------------------------------------------------------------------------
   25. SEARCH — persistent header bar + live suggestion dropdown
   -------------------------------------------------------------------------- */
.sx{
  position:relative;display:flex;align-items:center;gap:.5rem;flex:1;
  max-width:380px;margin-inline:auto;
  border:1px solid var(--line);border-radius:999px;
  background:var(--white);padding:.42rem .42rem .42rem .9rem;
  transition:border-color .35s var(--ease),box-shadow .35s var(--ease);
}
.sx:focus-within{border-color:var(--gold);box-shadow:0 0 0 3px rgba(200,178,108,.15)}
.sx .sx-i{color:var(--taupe);flex-shrink:0}
.sx input{
  flex:1;min-width:0;border:0;outline:none;background:transparent;
  font-size:.86rem;font-weight:300;color:var(--ink);padding:.18rem 0;
}
.sx input::placeholder{color:var(--taupe-lt)}
.sx input::-webkit-search-cancel-button{-webkit-appearance:none}
.sx button[type=submit]{
  flex-shrink:0;border-radius:999px;background:var(--ink);color:var(--gold-lt);
  font-size:.6rem;letter-spacing:.16em;text-transform:uppercase;font-weight:500;
  padding:.5em 1.05em;transition:background .35s var(--ease),color .35s var(--ease);
}
.sx button[type=submit]:hover{background:var(--gold-dp);color:#fff}

.sx-panel{
  position:absolute;top:calc(100% + .55rem);left:0;right:0;z-index:90;
  background:var(--porcelain);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:var(--sh-lg);overflow:hidden;max-height:min(64vh,430px);overflow-y:auto;
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .25s var(--ease),transform .25s var(--ease),visibility .25s;
}
.sx-panel.open{opacity:1;visibility:visible;transform:none}
.sx-row{
  display:flex;align-items:center;gap:.85rem;padding:.65rem .85rem;
  border-bottom:1px solid var(--line-2);transition:background .2s;
}
.sx-row:last-child{border-bottom:0}
.sx-row:hover,.sx-row.on{background:var(--porcelain-2)}
.sx-thumb{
  width:46px;height:46px;flex-shrink:0;border-radius:var(--r);overflow:hidden;
  background:var(--porcelain-2);display:grid;place-items:center;color:var(--gold-dp);
}
.sx-thumb img{width:100%;height:100%;object-fit:cover}
.sx-thumb svg{width:56%}
.sx-txt{display:flex;flex-direction:column;gap:.15rem;min-width:0}
.sx-txt b{font-weight:400;font-size:.88rem;color:var(--ink);line-height:1.25;
  overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.sx-txt small{font-size:.58rem;letter-spacing:.2em;text-transform:uppercase;color:var(--gold-dp)}
.sx-empty{padding:1.1rem .95rem;font-size:.85rem;color:var(--taupe)}
.sx-empty a{color:var(--wa-dp);border-bottom:1px solid currentColor}
.sx-clear{color:var(--gold-dp);border-bottom:1px solid currentColor}

/* the bar drops under the header row on tablet, and is full-width on phones */
@media (max-width:1080px){
  .nav{flex-wrap:wrap;height:auto;padding-block:.7rem;row-gap:.6rem}
  .sx{order:3;flex-basis:100%;max-width:none;margin:0}
}
@media (max-width:520px){
  .sx{padding-left:.75rem}
  .sx button[type=submit]{padding:.5em .85em}
}

/* --------------------------------------------------------------------------
   21. PRODUCT GRID POLISH
   The catalogue is where a buyer actually spends their time, so the motion
   budget belongs here rather than on another hero flourish. All of it is
   transform/opacity only, so it composites and never costs layout.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion:no-preference){

  /* Everything here rides --ease-out (an expo-out curve), moves a short
     distance over a long duration, and touches only transform/opacity so it
     stays on the compositor. Short+fast reads as a twitch; long+small reads
     as expensive. `backface-visibility` kills the sub-pixel shimmer that
     otherwise shows on a scaling photo. */
  .pgrid > .card,.prail > .card{backface-visibility:hidden}

  /* cards glide up a beat apart across each row, so a long grid reads as a
     sequence rather than a wall arriving at once. Containers are .pgrid
     (catalogue) and .prail (the home rails) — not a generic .grid. */
  .pgrid > .card.in,.prail > .card.in{animation:cardIn .9s var(--ease-out) both}
  .pgrid > .card.in:nth-child(4n+2),.prail > .card.in:nth-child(4n+2){animation-delay:.07s}
  .pgrid > .card.in:nth-child(4n+3),.prail > .card.in:nth-child(4n+3){animation-delay:.14s}
  .pgrid > .card.in:nth-child(4n+4),.prail > .card.in:nth-child(4n+4){animation-delay:.21s}
  @keyframes cardIn{from{opacity:0;transform:translate3d(0,18px,0) scale(.99)}to{opacity:1;transform:none}}

  /* the whole card lifts on a single curve — shadow, photo and name all move
     together, which is what separates a considered hover from a wobbly one */
  .card{transition:transform .6s var(--ease-out),box-shadow .6s var(--ease-out)}
  .card:hover{transform:translate3d(0,-6px,0);box-shadow:0 26px 60px -28px rgba(43,43,36,.42)}
  /* Slow the existing img-main / img-alt crossfade rather than adding a second
     zoom on top of it — style.css already swaps to the alternate angle on
     hover, and two competing transforms on the same element is what makes a
     hover feel cheap. */
  .card .media img{transition:opacity .75s var(--ease-out),transform 1.1s var(--ease-out);will-change:transform,opacity}

  /* A slow light sweep across the photo — the detail that reads as luxury
     retail. This must be ::before: style.css already uses .media::after for
     the card's 1px border and its gold hover, and overriding that would quietly
     delete the border. Sits under .badges (z-index 3) and ignores pointers. */
  .card .media::before{
    content:"";position:absolute;inset:0;pointer-events:none;z-index:2;
    background:linear-gradient(105deg,transparent 38%,rgba(255,255,255,.28) 50%,transparent 62%);
    transform:translateX(-120%);transition:transform 1.15s var(--ease-out);
  }
  .card:hover .media::before{transform:translateX(120%)}

  /* the product name draws its gold rule left to right */
  .card .pname{background-image:linear-gradient(var(--gold),var(--gold));
    background-size:0 1px;background-position:0 100%;background-repeat:no-repeat;
    transition:background-size .7s var(--ease-out)}
  .card:hover .pname{background-size:100% 1px}

  /* badges drop in behind the card, and the saved-heart settles rather than pops */
  .card.in .badges > *{animation:badgeIn .7s var(--ease-out) both;animation-delay:.16s}
  @keyframes badgeIn{from{opacity:0;transform:translate3d(0,-10px,0)}to{opacity:1;transform:none}}
  /* the heart is hidden and offset until hover in style.css — keep the
     translateY(0) it settles to, and only add the scale on top */
  .card .wish{transition:transform .55s var(--ease-out),opacity .55s var(--ease-out)}
  .card:hover .wish{transform:translateY(0) scale(1.06)}

  /* the enquiry button fills from the left instead of just changing colour */
  .card .buys .btn{position:relative;overflow:hidden;isolation:isolate}
  .card .buys .btn::after{
    content:"";position:absolute;inset:0;z-index:-1;background:var(--gold-dp,#9C8547);
    transform:scaleX(0);transform-origin:left;transition:transform .6s var(--ease-out);
  }
  .card .buys .btn:hover::after{transform:scaleX(1)}

  /* filter chips: a slow settle on hover, a quick answer on tap. The press
     stays short on purpose — feedback has to feel instant, motion does not. */
  .chip{transition:border-color .45s var(--ease),color .45s var(--ease),
    background .45s var(--ease),transform .5s var(--ease-out)}
  .chip:hover{transform:translate3d(0,-2px,0)}
  .chip:active{transform:scale(.95);transition-duration:.12s}

  /* drawer rows cascade in when the mobile menu opens */
  .drawer.open nav > *{animation:drawIn .68s var(--ease-out) both}
  .drawer.open nav > :nth-child(n+2){animation-delay:calc(.028s * var(--i,1))}
  @keyframes drawIn{from{opacity:0;transform:translate3d(14px,0,0)}to{opacity:1;transform:none}}

  /* section eyebrows draw their gold rule as the heading arrives */
  .shead .eyebrow::before,.page-head .eyebrow::before{transition:transform .9s var(--ease-out) .1s}
}

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){
    /* These are glued to the scroll position rather than fired once, so they
       track the thumb exactly — no easing mismatch between finger and page.
       Browsers without support skip the block and keep the JS reveals. */

    /* section headings track the scroll instead of firing once */
    .shead .st{
      animation:sheadIn linear both;
      animation-timeline:view();
      animation-range:entry 5% entry 70%;
    }
    @keyframes sheadIn{from{opacity:0;transform:translate3d(0,26px,0)}to{opacity:1;transform:none}}

    /* brand wall cards settle as they arrive */
    .bcard{
      animation:bcardIn linear both;
      animation-timeline:view();
      animation-range:entry 0% entry 60%;
    }
    @keyframes bcardIn{from{opacity:0;transform:translate3d(0,30px,0) scale(.97)}to{opacity:1;transform:none}}

    /* No scroll-driven drift on .card .media img: an animation beats a plain
       declaration in the cascade, so it would win over the img-main/img-alt
       hover crossfade in style.css and freeze the swap. The hover zoom there
       is the better effect — leave it alone.  */

    /* the shade wall fills in swatch by swatch as it comes up */
    .sw{
      animation:swIn linear both;
      animation-timeline:view();
      animation-range:entry 10% entry 80%;
    }
    @keyframes swIn{from{opacity:0;transform:translate3d(0,14px,0) scale(.9)}to{opacity:1;transform:none}}

    /* the announcement rule and section eyebrows draw themselves */
    .eyebrow{
      animation:eyebrowIn linear both;
      animation-timeline:view();
      animation-range:entry 0% entry 55%;
    }
    @keyframes eyebrowIn{from{opacity:0;letter-spacing:.42em}to{opacity:1}}
  }
}

/* --------------------------------------------------------------------------
   21b. PRODUCT SCROLL CHOREOGRAPHY
   Every effect in section 21 above hangs off :hover — which means on a phone
   none of them ever fire, and roughly half the catalogue's motion simply did
   not exist. A touch device has no hover, but it always has scroll position,
   so here the scroll drives the same choreography.

   These are `animation-timeline: view()`, so the browser runs them on the
   compositor against scroll offset rather than on a timer. They stay glued to
   the thumb, cost no main-thread work, and cannot drift out of sync.

   Failure mode to respect: an animation beats a plain declaration in the
   cascade, so anything applied to `.media img` would win over the img-main /
   img-alt hover crossfade in style.css and freeze the swap. That is why the
   photo rules live inside `@media (hover:none)` — desktop keeps its crossfade,
   touch gets the scroll settle instead.
   -------------------------------------------------------------------------- */
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion:no-preference){

    /* Cards travel in against scroll on every device, replacing the timed
       .card.in entrance — two animations on one element is what makes a grid
       look like it is stuttering.

       CRITICAL: this animates TRANSFORM ONLY, never opacity. Visibility stays
       owned by the .reveal / .reveal.in pair that the JS engine drives, because
       that engine carries a 3-second hard-reveal timeout so a card can never be
       left invisible. An opacity keyframe here overrides that safety net, and
       measurement showed exactly that failing: cards sitting mid-screen at
       opacity 0 on a phone. A missing animation is a blemish; an invisible
       product is a lost order.

       Both selectors carry the rule so it survives .in being added — a bare
       `.pgrid > .card` would lose to `.pgrid > .card.in` in section 21. */
    .pgrid > .card,
    .pgrid > .card.in{
      animation:cardTravel linear both;
      animation-timeline:view();
      animation-range:entry 0% entry 58%;
    }
    @keyframes cardTravel{
      from{transform:translate3d(0,46px,0) scale(.94)}
      to{transform:none}
    }
  }
}

@media (hover:none){
  @supports (animation-timeline: view()){
    @media (prefers-reduced-motion:no-preference){

      /* the photo settles out of a slow push-in as the card rises */
      .pgrid > .card .media img{
        animation:mediaSettle linear both;
        animation-timeline:view();
        animation-range:entry 0% cover 40%;
      }
      @keyframes mediaSettle{from{transform:scale(1.12)}to{transform:scale(1)}}

      /* each photo catches the light as it crosses the middle of the screen —
         on desktop this is the hover sweep, here the scroll performs it */
      .pgrid > .card .media::before{
        animation:cardSweep linear both;
        animation-timeline:view();
        animation-range:cover 20% cover 70%;
      }
      @keyframes cardSweep{from{transform:translateX(-125%)}to{transform:translateX(125%)}}

      /* and the gold rule draws itself under the product name */
      .pgrid > .card .pname{
        animation:ruleDrawIn linear both;
        animation-timeline:view();
        animation-range:entry 40% cover 15%;
      }
      @keyframes ruleDrawIn{from{background-size:0 1px}to{background-size:100% 1px}}

      /* the card lifts off the page at the point it is most readable, then
         sets back down — the touch equivalent of a hover lift. Same rule on
         both selectors, and still no opacity anywhere near it. */
      .pgrid > .card,
      .pgrid > .card.in{
        animation:cardTravel linear both,cardLift linear both;
        animation-timeline:view(),view();
        animation-range:entry 0% entry 58%,cover 25% cover 75%;
      }
      @keyframes cardLift{
        0%{box-shadow:0 0 0 0 rgba(43,43,36,0)}
        50%{box-shadow:0 22px 46px -26px rgba(43,43,36,.34)}
        100%{box-shadow:0 0 0 0 rgba(43,43,36,0)}
      }
    }
  }

  /* Not everything can wait for scroll. These are pressed, so they answer
     instantly — a tap with no feedback reads as a broken button. */
  .card .buys .btn:active::after{transform:scaleX(1)}
  .card .wish:active{transform:translateY(0) scale(1.14)}
  .askwa:active,.askwa-inline:active{gap:.7em}
}

/* --------------------------------------------------------------------------
   28. POINTER TILT ON PRODUCT CARDS  (fine pointers only)
   motion.js writes --rx / --ry from the cursor's position inside the card.
   A small rotation on a long perspective reads as depth; anything more reads
   as a gimmick, so this tops out at a few degrees.
   -------------------------------------------------------------------------- */
@media (hover:hover) and (pointer:fine){
  @media (prefers-reduced-motion:no-preference){
    .pgrid,.prail{perspective:1400px}
    .card.tilt{
      transform:rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg)) translate3d(0,-6px,0);
      transition:transform .18s linear,box-shadow .6s var(--ease-out);
      transform-style:preserve-3d;
    }
    /* the photo floats a touch in front of the card body */
    .card.tilt .media{transform:translateZ(26px)}
    .card.tilt .badges{transform:translateZ(42px)}
    /* leaving the card hands control back to the smooth hover transition */
    .card:not(.tilt){transition:transform .6s var(--ease-out),box-shadow .6s var(--ease-out)}
  }
}

/* --------------------------------------------------------------------------
   29. AURORA — a slow brass bloom behind the dark bands
   Two oversized radial gradients drifting on different periods. Pure
   transform/opacity on a pseudo-element, so it composites and never repaints.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion:no-preference){
  .band-dark,.cta-band,.vband,.footer{position:relative;isolation:isolate}
  .band-dark::after,.cta-band::after,.footer::after{
    content:"";position:absolute;inset:-30%;z-index:0;pointer-events:none;
    background:
      radial-gradient(38% 44% at 22% 30%,rgba(200,178,108,.20),transparent 62%),
      radial-gradient(32% 38% at 78% 68%,rgba(129,143,134,.18),transparent 64%);
    animation:aurora 26s ease-in-out infinite alternate;
    will-change:transform;
  }
  @keyframes aurora{
    0%  {transform:translate3d(-3%,-2%,0) scale(1)}
    50% {transform:translate3d(4%,3%,0) scale(1.12)}
    100%{transform:translate3d(-2%,4%,0) scale(1.04)}
  }
  /* keep the aurora behind the content of those sections */
  .band-dark > *,.cta-band > *,.footer > *{position:relative;z-index:1}
}

/* --------------------------------------------------------------------------
   30. PAGE TRANSITION — a brass curtain on internal navigation
   motion.js holds the click, plays this, then follows the link.
   -------------------------------------------------------------------------- */
.pcurtain{
  position:fixed;inset:0;z-index:300;pointer-events:none;
  background:linear-gradient(115deg,var(--ink) 0%,var(--ink-2) 58%,var(--gold-dp) 150%);
  transform:translateY(100%);
}
.pcurtain.in{animation:curtainIn .52s var(--ease-out) forwards}
.pcurtain.out{animation:curtainOut .62s var(--ease-out) forwards}
@keyframes curtainIn{to{transform:translateY(0)}}
@keyframes curtainOut{from{transform:translateY(0)}to{transform:translateY(-100%)}}
@media (prefers-reduced-motion:reduce){.pcurtain{display:none}}

/* --------------------------------------------------------------------------
   31. RATE-LIST POPUP
   Exit-intent on desktop, timed/scroll on touch. Once per visitor.
   -------------------------------------------------------------------------- */
.lead{
  position:fixed;inset:0;z-index:220;display:grid;place-items:center;padding:1.2rem;
  background:rgba(30,30,24,.62);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  opacity:0;visibility:hidden;transition:opacity .45s var(--ease),visibility .45s;
}
.lead.show{opacity:1;visibility:visible}
.lead-box{
  position:relative;width:min(430px,100%);background:var(--porcelain);
  border:1px solid var(--line-gold);border-radius:var(--r);
  padding:2.3rem 1.9rem 1.7rem;box-shadow:0 40px 90px -40px rgba(30,30,24,.6);
  transform:translateY(22px) scale(.97);transition:transform .55s var(--ease-out);
}
.lead.show .lead-box{transform:none}
.lead-x{
  position:absolute;top:.7rem;right:.9rem;font-size:1.5rem;line-height:1;
  color:var(--taupe);background:none;border:0;cursor:pointer;transition:color .3s;
}
.lead-x:hover{color:var(--ink)}
.lead-eyebrow{
  display:block;font-size:.56rem;letter-spacing:.28em;text-transform:uppercase;
  color:var(--gold-dp);margin-bottom:.7rem;
}
.lead-box h3{font-family:"Playfair Display",serif;font-size:1.85rem;font-weight:400;line-height:1.1;color:var(--ink)}
.lead-box p{margin:.6rem 0 1.3rem;font-size:.87rem;line-height:1.55;color:var(--taupe)}
.lead-form{display:flex;flex-direction:column;gap:.6rem}
.lead-form input{
  width:100%;padding:.78em .95em;border:1px solid var(--line);border-radius:var(--r);
  background:#fff;font-size:.85rem;color:var(--ink);transition:border-color .35s;
}
.lead-form input::placeholder{color:var(--taupe)}
.lead-form input:focus{outline:none;border-color:var(--gold)}
.lead-form .btn{margin-top:.35rem}
.lead-fine{display:block;margin-top:.9rem;font-size:.66rem;color:var(--taupe);text-align:center}
@media (max-width:480px){ .lead-box{padding:2rem 1.35rem 1.4rem} .lead-box h3{font-size:1.6rem} }
@media (prefers-reduced-motion:reduce){.lead{display:none}}

/* --------------------------------------------------------------------------
   13. REDUCED MOTION — everything above collapses to static
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  .pgrid > .card.in,.prail > .card.in{animation:none}
  .card,.card:hover{transform:none;box-shadow:none}
  .card .media::before{display:none}
  .card.in .badges > *{animation:none}
  .card:hover .wish{transform:none}
  .card:hover .pname{background-size:0 1px}
  .chip:hover{transform:none}
  .drawer.open nav > *{animation:none}
  .intro{display:none}
  .wi{transform:none!important;opacity:1!important}
  .rv,.stagger > *{opacity:1!important;transform:none!important}
  .curtain::after{display:none}
  .curtain img,.curtain video{transform:none!important}
  .sheen{animation:none}
  .kcur,.kcur-ring{display:none}
  .card:hover .media{transform:none}
  .vband video{display:none}
  .sw{opacity:1!important;transform:none!important}
  .kprog{display:none}
}
/* --------------------------------------------------------------------------
   32. IMAGE ZOOM / LIGHTBOX
   The client's words: "The image don't get zoomed. In gel polish all people
   want to see the product in zoom style." Tapping any product photo now opens
   it full-screen, and on the second tap (or scroll wheel) it magnifies to 2.5x
   and pans with the pointer — because on a gel polish the buyer is trying to
   read a shade number off the bottle.
   -------------------------------------------------------------------------- */
.zoomer{
  position:fixed;inset:0;z-index:260;display:grid;place-items:center;
  background:rgba(24,24,19,.94);
  opacity:0;visibility:hidden;transition:opacity .35s var(--ease),visibility .35s;
  cursor:zoom-in;overscroll-behavior:contain;
}
.zoomer.show{opacity:1;visibility:visible}
.zoomer img{
  max-width:94vw;max-height:86vh;object-fit:contain;display:block;
  transition:transform .45s var(--ease-out);transform-origin:center center;
  will-change:transform;-webkit-user-select:none;user-select:none;
}
.zoomer.mag{cursor:zoom-out}
.zoomer.mag img{transition:transform .12s linear}
.zoomer .zx{
  position:absolute;top:1rem;right:1.15rem;z-index:2;
  width:44px;height:44px;display:grid;place-items:center;border:0;cursor:pointer;
  background:rgba(248,247,242,.1);color:var(--porcelain);border-radius:50%;
  font-size:1.5rem;line-height:1;transition:background .3s;
}
.zoomer .zx:hover{background:rgba(248,247,242,.22)}
.zoomer .zcap{
  position:absolute;left:0;right:0;bottom:1.1rem;text-align:center;pointer-events:none;
  font-size:.62rem;letter-spacing:.22em;text-transform:uppercase;color:rgba(248,247,242,.6);
}
.zoomer .zhint{
  position:absolute;left:50%;top:1.2rem;transform:translateX(-50%);
  font-size:.56rem;letter-spacing:.24em;text-transform:uppercase;color:rgba(226,211,160,.75);
  pointer-events:none;transition:opacity .4s;
}
.zoomer.mag .zhint{opacity:0}
/* video slide inside the zoomer — sized like the photo, magnify hint off */
.zoomer .zvid{max-width:94vw;max-height:86vh;display:block;background:#000}
.zoomer.zv .zhint{display:none}
.zoomer.zv{cursor:default}
/* the card photo now signals it is tappable */
@media (hover:hover){ .card .media{cursor:zoom-in} }
@media (prefers-reduced-motion:reduce){ .zoomer img{transition:none} }
/* gallery navigation inside the zoomer */
.zoomer .znav button{
  position:absolute;top:50%;transform:translateY(-50%);z-index:3;
  width:46px;height:46px;display:grid;place-items:center;border:0;cursor:pointer;
  background:rgba(248,247,242,.12);color:var(--porcelain);border-radius:50%;
  font-size:1.15rem;line-height:1;transition:background .3s;
}
.zoomer .znav button:hover{background:rgba(248,247,242,.26)}
.zoomer .zp{left:.9rem}
.zoomer .zn{right:.9rem}
.zoomer.mag .znav{display:none!important}
.zoomer .zdots{
  position:absolute;left:0;right:0;bottom:2.6rem;z-index:2;pointer-events:none;
  display:flex;justify-content:center;gap:.45rem;
}
.zoomer .zdots i{
  width:7px;height:7px;border-radius:50%;background:rgba(248,247,242,.35);
  transition:background .3s,transform .3s;
}
.zoomer .zdots i.on{background:var(--gold);transform:scale(1.25)}
.zoomer.mag .zdots{display:none}
@media (max-width:640px){ .zoomer .znav button{width:40px;height:40px} }
