/* ═══════════════════════════════════════════════════════════
   ASIF — MOTION LAYER  (shared, link this from every page)
   ────────────────────────────────────────────────────────────
   Quiet, expensive motion. Nothing flashy: small distances,
   long cubic easings, fades and lifts that read as silk on
   wood, not glass on rails. All of it gated behind
   `prefers-reduced-motion: no-preference` so accessibility
   gets a still site, never a broken one.

   Conventions:
     • .reveal               — scroll-revealed (fades + 12px up)
     • .reveal-d-{1..6}      — staggered children (60ms steps)
     • .tactile              — buttons/CTAs that press inward
     • .lift                 — cards that rise on hover
     • .lift-soft            — same, lighter shadow
     • .heart-pop            — wishlist heart ripple on toggle
     • .pulse-dot            — Margaux/online status pulse
     • .shimmer              — AI "thinking" loader stripe
     • .badge-bounce         — cart count change
     • .img-zoom             — gentle Ken-Burns zoom on hover
     • .underline-grow       — link gold underline grow
     • [data-page-fade]      — body fade-in on first paint
   ═══════════════════════════════════════════════════════════ */

:root {
  --motion-ease:     cubic-bezier(0.2, 0.8, 0.2, 1);
  --motion-ease-in:  cubic-bezier(0.55, 0, 0.2, 1);
  --motion-fast:     180ms;
  --motion-med:      320ms;
  --motion-slow:     560ms;
  --motion-rest:     900ms;
}

/* ─────────── page entrance ─────────── */
@keyframes asifPageFade {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
[data-page-fade] {
  animation: asifPageFade var(--motion-rest) var(--motion-ease) both;
}

/* ─────────── scroll-reveal ─────────── */
/* Distance rides the FX intensity token from global.css (Medium: 16px) */
.reveal {
  opacity: 0;
  transform: translateY(var(--fx-reveal-dist, 14px));
  transition:
    opacity var(--motion-rest) var(--motion-ease),
    transform var(--motion-rest) var(--motion-ease);
  will-change: opacity, transform;
}
.reveal.is-in { opacity: 1; transform: none; }

/* staggered children — apply .reveal to a row then .reveal-d-* to each */
.reveal-d-1 { transition-delay:  60ms; }
.reveal-d-2 { transition-delay: 120ms; }
.reveal-d-3 { transition-delay: 180ms; }
.reveal-d-4 { transition-delay: 240ms; }
.reveal-d-5 { transition-delay: 300ms; }
.reveal-d-6 { transition-delay: 360ms; }

/* ─────────── tactile press (CTAs, icon buttons) ─────────── */
.tactile {
  transition:
    transform var(--motion-fast) var(--motion-ease),
    box-shadow var(--motion-med) var(--motion-ease),
    background-color var(--motion-med) var(--motion-ease),
    color var(--motion-med) var(--motion-ease),
    border-color var(--motion-med) var(--motion-ease);
}
.tactile:hover  { transform: translateY(-1px); }
.tactile:active { transform: translateY(0) scale(0.985); }

/* ─────────── card lift on hover ─────────── */
.lift {
  transition:
    transform var(--motion-med) var(--motion-ease),
    box-shadow var(--motion-med) var(--motion-ease),
    border-color var(--motion-med) var(--motion-ease);
}
.lift:hover {
  transform: translateY(-3px);
  box-shadow: 0 18px 38px rgba(26, 23, 20, 0.10);
}
.lift-soft {
  transition:
    transform var(--motion-med) var(--motion-ease),
    box-shadow var(--motion-med) var(--motion-ease);
}
.lift-soft:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 24px rgba(26, 23, 20, 0.07);
}

/* ─────────── image gentle zoom ─────────── */
.img-zoom { overflow: hidden; }
.img-zoom > img,
.img-zoom > .img-zoom__img {
  transition: transform 700ms var(--motion-ease);
  will-change: transform;
}
.img-zoom:hover > img,
.img-zoom:hover > .img-zoom__img { transform: scale(1.045); }

/* ─────────── gold underline grow ─────────── */
.underline-grow {
  position: relative;
  display: inline-block;
}
.underline-grow::after {
  content: '';
  position: absolute;
  left: 0;
  right: 100%;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  opacity: 0.55;
  transition: right var(--motion-med) var(--motion-ease);
}
.underline-grow:hover::after { right: 0; }

/* ─────────── heart ripple on toggle ─────────── */
@keyframes asifHeartPop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.32); }
  100% { transform: scale(1); }
}
@keyframes asifHeartRipple {
  from { transform: scale(0.6); opacity: 0.55; }
  to   { transform: scale(2.4); opacity: 0; }
}
.heart-pop  { animation: asifHeartPop 420ms var(--motion-ease); }
.heart-ripple {
  position: absolute; inset: 0; border-radius: 50%;
  background: rgba(184, 150, 90, 0.45);
  animation: asifHeartRipple 620ms var(--motion-ease) forwards;
  pointer-events: none;
}

/* ─────────── live "online" dot pulse (concierge, advisor) ─────────── */
@keyframes asifPulseDot {
  0%        { transform: scale(1);   opacity: 0.55; }
  70%, 100% { transform: scale(2.4); opacity: 0;    }
}
.pulse-dot { position: relative; display: inline-block; }
.pulse-dot::after {
  content: '';
  position: absolute; inset: 0; border-radius: 50%;
  background: currentColor;
  animation: asifPulseDot 2.2s var(--motion-ease) infinite;
}

/* ─────────── cart badge bounce on count change ─────────── */
@keyframes asifBadgeBounce {
  0%   { transform: scale(0.5); opacity: 0; }
  60%  { transform: scale(1.18); opacity: 1; }
  100% { transform: scale(1);    opacity: 1; }
}
.badge-bounce { animation: asifBadgeBounce 340ms var(--motion-ease); }

/* The Ingathering count badge: a single, quiet 200ms scale pulse on change —
   nothing more (work order §2). Re-keyed by count so it replays each add. */
@keyframes asifCartBadge {
  0%   { transform: scale(0.65); }
  55%  { transform: scale(1.15); }
  100% { transform: scale(1); }
}
.asif-cart-badge { animation: asifCartBadge 200ms var(--motion-ease); }

/* ─────────── shimmer (AI thinking, loading rails) ─────────── */
@keyframes asifShimmer {
  0%   { background-position: -120% 0; }
  100% { background-position:  220% 0; }
}
.shimmer {
  background-image: linear-gradient(
    90deg,
    rgba(184,150,90,0)    0%,
    rgba(184,150,90,0.22) 50%,
    rgba(184,150,90,0)    100%
  );
  background-size: 220% 100%;
  animation: asifShimmer 1.6s linear infinite;
}

/* ─────────── thread bubble entrance (concierge) ─────────── */
@keyframes asifBubbleIn {
  from { opacity: 0; transform: translateY(8px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
.bubble-in { animation: asifBubbleIn 360ms var(--motion-ease) both; }

/* ─────────── soft press ring for icons ─────────── */
.icon-press {
  border-radius: 999px;
  transition: background-color var(--motion-med) var(--motion-ease),
              transform var(--motion-fast) var(--motion-ease);
}
.icon-press:hover  { background-color: rgba(184, 150, 90, 0.10); }
.icon-press:active { transform: scale(0.92); }

/* ─────────── pointer tilt + specular (depth layer) ───────────
   asif-motion.js writes --tilt-rx/--tilt-ry (−1..1) and --spec-x/y
   onto [data-fx-tilt]; the tier token --fx-tilt-max (global.css)
   clamps the angle. Decorative only — aria-hidden not needed since
   the wrapper is the card's own content container. */
[data-fx-tilt] {
  transform: perspective(900px)
    rotateX(calc(var(--tilt-rx, 0) * var(--fx-tilt-max, 7deg)))
    rotateY(calc(var(--tilt-ry, 0) * var(--fx-tilt-max, 7deg)));
  transition: transform 180ms var(--motion-ease);
  will-change: transform;
}
[data-fx-tilt]::after {
  content: '';
  position: absolute; inset: 0; z-index: 3;
  pointer-events: none;
  background: radial-gradient(240px circle at var(--spec-x, 50%) var(--spec-y, 40%),
    rgba(217, 190, 134, var(--fx-sheen-opacity, 0.28)), transparent 62%);
  opacity: 0;
  transition: opacity 300ms var(--motion-ease);
  mix-blend-mode: soft-light;
}
[data-fx-tilt]:hover::after { opacity: 1; }
@media (prefers-reduced-motion: reduce), (hover: none) {
  [data-fx-tilt] { transform: none !important; }
  [data-fx-tilt]::after { display: none; }
}

/* ─────────── The Ingathering — cart motion ───────────
   Deliberate, minimal (work order §2). The drawer arrives like a door
   drawn open, not a spring; items settle onto the table once, on the
   first opening only (the JS toggles .asif-cart-settle). Everything
   here is flattened by the reduced-motion block below. */
/* ── Geometry: a right-side drawer on desktop … ── */
.asif-cart-drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: 420px; max-width: 92vw;
  box-shadow: -24px 0 60px rgba(0, 0, 0, 0.4);
  transform: translateX(468px);              /* width + 48, parked off-screen right */
  transition: transform 260ms cubic-bezier(0.32, 0.72, 0, 1);
  will-change: transform;
}
.asif-cart-drawer.is-open { transform: translateX(0); }

/* … a slide-up sheet on phone / tablet (work order §6). Anchored to the
   bottom, full-width, rounded at the top, capped so the scrim still frames
   it, and padded for the iOS home indicator. */
@media (max-width: 1024px) {
  .asif-cart-drawer {
    top: auto; right: 0; left: 0; bottom: 0;
    width: 100%; max-width: 100%;
    max-height: min(92vh, 760px);
    border-radius: 18px 18px 0 0;
    box-shadow: 0 -20px 60px rgba(0, 0, 0, 0.42);
    transform: translateY(100%);
  }
  .asif-cart-drawer.is-open { transform: translateY(0); }
}
.asif-cart-scrim {
  background: rgba(28, 26, 23, 0.6);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  transition: opacity 260ms ease;
}
@keyframes asifCartSettle {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
.asif-cart-settle > * {
  animation: asifCartSettle 320ms var(--motion-ease) both;
}
.asif-cart-settle > *:nth-child(2)  { animation-delay: 30ms; }
.asif-cart-settle > *:nth-child(3)  { animation-delay: 60ms; }
.asif-cart-settle > *:nth-child(4)  { animation-delay: 90ms; }
.asif-cart-settle > *:nth-child(5)  { animation-delay: 120ms; }
.asif-cart-settle > *:nth-child(6)  { animation-delay: 150ms; }
.asif-cart-settle > *:nth-child(n+7){ animation-delay: 180ms; }
/* subtotal / any money that changes: cross-fade, never a count-up */
.asif-cart-xfade { transition: opacity 120ms ease; }
.asif-cart-xfade.is-stale { opacity: 0; }
/* free-shipping progress fill */
.asif-cart-progress-fill { transition: width 400ms ease-out; }
/* line removal: the row folds closed, then the store drops it */
.asif-cart-line-leave {
  transition: opacity 200ms ease, transform 200ms ease,
              max-height 200ms ease, margin 200ms ease, padding 200ms ease;
  opacity: 0 !important;
  transform: translateX(12px);
  max-height: 0 !important;
  overflow: hidden;
  margin-top: 0 !important; margin-bottom: 0 !important;
  padding-top: 0 !important; padding-bottom: 0 !important;
}

/* ─────────── focus ring (a11y) ─────────── */
:focus-visible {
  outline: 2px solid rgba(184, 150, 90, 0.85);
  outline-offset: 3px;
  border-radius: 3px;
}

/* ─────────── REDUCED MOTION — kill everything decorative ─────────── */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal { opacity: 1 !important; transform: none !important; }
  [data-page-fade] { animation: none !important; }
  .pulse-dot::after { display: none !important; }
}

/* ═══════════════════════════════════════════════════════════
   MOBILE LAYER — shared phone-only fixes that don't belong
   inside an individual page's <style>. Page-scoped breakpoints
   stay where they are; this is for the global chrome.
   ═══════════════════════════════════════════════════════════ */

/* Phone layer kicks in below 640px */
@media (max-width: 640px) {
  /* tighten the section padding token if a page uses it */
  :root { --section-padding: 56px; }

  /* Concierge panel: full-bleed side drawer on phone.
     The cart ([data-asif-drawer]) is intentionally NOT here — it is a
     bottom slide-up sheet with its own geometry (rounded top, safe-area),
     defined in the cart-motion block above (work order §6). */
  aside[aria-label="Your room"],
  aside[aria-label="Concierge"] {
    width: 100vw !important;
    max-width: 100vw !important;
    border-radius: 0 !important;
  }
}

/* small-phone narrow column */
@media (max-width: 380px) {
  aside[aria-label="Your room"] > div,
  aside[aria-label="Concierge"] > div {
    padding-left: 18px !important;
    padding-right: 18px !important;
  }
}

/* ═══════════════════════════════════════════════════════════
   MIX CARD — when expanded on phone, fall back to single column.
   The card sets data-mix-card + data-mix-open at runtime; we
   override its inline gridColumn:span 2 below 720px so the
   neighboring track isn't created. The expanded right-panel
   wraps below the hero on its own thanks to the card's grid
   template (1.05fr 1fr) becoming 1fr / 1fr at this width.
   ═══════════════════════════════════════════════════════════ */
@media (max-width: 720px) {
  [data-mix-card][data-mix-open="true"] {
    grid-column: span 1 !important;
  }
  [data-mix-card][data-mix-open="true"] > div[style*="grid-template-columns"] {
    grid-template-columns: 1fr !important;
    column-gap: 0 !important;
    row-gap: 18px !important;
  }
}
