/* ===== Amino House — Motion system =====================================
   Confirmation & celebration motion. Character: precise, quick, calm —
   150–300ms, gentle decelerate, no bounce, no confetti. A well-machined
   instrument responding, not a consumer app celebrating.
   Every animation here has a prefers-reduced-motion fallback at the bottom
   of this file (instant state change, no movement).
   ====================================================================== */
:root{
  /* Durations */
  --dur-instant:90ms;   /* micro state (checkbox tick) */
  --dur-quick:150ms;    /* hover, selection settle */
  --dur-base:220ms;     /* standard state change */
  --dur-calm:300ms;     /* entrance, panel reveal */
  --dur-draw:600ms;     /* checkmark stroke draw */
  --dur-fly:620ms;      /* fly-to-cart arc */
  --dur-hold:1400ms;    /* how long a button holds its confirm state */
  --dur-tint:900ms;     /* new-cart-line highlight fade */
  /* Easings */
  --ease-out:cubic-bezier(.22,.61,.36,1);   /* calm decelerate — default */
  --ease-inout:cubic-bezier(.4,0,.2,1);     /* symmetrical moves */
  /* Rhythm */
  --stagger:60ms;
}

/* --- Keyframes -------------------------------------------------------- */
@keyframes ahRise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@keyframes ahFade{from{opacity:0}to{opacity:1}}
@keyframes ahPulse{0%{transform:scale(1)}42%{transform:scale(1.13)}100%{transform:scale(1)}}
@keyframes ahBadge{0%{opacity:0;transform:translate(12px,-16px) scale(.7)}60%{opacity:1}100%{opacity:1;transform:translate(12px,-10px) scale(1)}}
@keyframes ahPop{from{opacity:0;transform:scale(.86)}to{opacity:1;transform:scale(1)}}
@keyframes ahDraw{to{stroke-dashoffset:0}}
@keyframes ahTint{0%{background:color-mix(in oklab,var(--accent) 9%,#fff)}100%{background:transparent}}
@keyframes ahSettle{from{transform:scale(.94)}to{transform:scale(1)}}
@keyframes ahNum{from{opacity:.45;transform:translateY(-3px)}to{opacity:1;transform:none}}
@keyframes ahSheen{from{transform:translateX(-101%)}to{transform:translateX(101%)}}

/* --- 1. ADD TO CART ---------------------------------------------------
   Sequence (calm default): button confirm 0ms → cart icon pulse 60ms →
   badge count in 60ms → drawer opens, new line tinted 900ms.
   With fly-to-cart on, the pulse waits for the arc to land (620ms).      */

/* Button briefly becomes its own confirmation. The ::after overlay means
   a React re-render can't clobber the state (className prop is untouched). */
.btn.is-added{position:relative;pointer-events:none}
.btn.is-added::after{
  content:attr(data-added);
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:7px;
  background:var(--ink);color:#fff;border-radius:inherit;
  font:inherit;font-size:inherit;font-weight:inherit;letter-spacing:inherit;
  animation:ahFade var(--dur-base) var(--ease-out);
}
.btn-ghost.is-added::after{background:#fff;color:var(--ink);border:1px solid var(--ink)}

/* Cart icon — a single calm pulse as the item lands. */
.icon-btn.ah-pulse svg{animation:ahPulse 260ms var(--ease-inout)}
/* Badge count animates in rather than hard-swapping (remounted by key). */
.cart-count{animation:ahBadge var(--dur-base) var(--ease-out)}

/* Fly-to-cart ghost (variant — off by default; window.AH_FLY_TO_CART). */
.ah-fly{position:fixed;z-index:200;pointer-events:none;border-radius:12px;object-fit:contain;will-change:transform,opacity}

/* New drawer line: brief accent tint so the eye finds WHAT was added.
   Multiple items added at once each animate — they stagger naturally by
   DOM order via the delay below. */
.cart-item--new{animation:ahTint var(--dur-tint) var(--ease-out)}
.cart-item--new:nth-child(2){animation-delay:80ms}
.cart-item--new:nth-child(3){animation-delay:160ms}
.cart-item--new:nth-child(n+4){animation-delay:240ms}
/* Line price + qty value re-key on change — the number arrives, never jumps. */
.cart-price,.cart-step-num{animation:ahNum var(--dur-base) var(--ease-out)}

/* --- 2. ORDER PLACED --------------------------------------------------
   Checkmark draws itself (600ms), then the page rises in, staggered.
   Pure CSS — nth-child stagger, no JSX timing to maintain.               */
.oc-check svg path{stroke-dasharray:26;stroke-dashoffset:26;animation:ahDraw var(--dur-draw) var(--ease-out) 120ms forwards}
.oc-hero>*,.oc-grid>*{animation:ahRise var(--dur-calm) var(--ease-out) backwards}
.oc-hero>.oc-check{animation:ahPop var(--dur-calm) var(--ease-out) backwards}
.oc-hero>*:nth-child(1){animation-delay:0ms}
.oc-hero>*:nth-child(2){animation-delay:calc(var(--stagger)*5)}
.oc-hero>*:nth-child(3){animation-delay:calc(var(--stagger)*6)}
.oc-hero>*:nth-child(4){animation-delay:calc(var(--stagger)*7)}
.oc-hero>*:nth-child(5){animation-delay:calc(var(--stagger)*8)}
.oc-grid>*:nth-child(1){animation-delay:calc(var(--stagger)*9)}
.oc-grid>*:nth-child(2){animation-delay:calc(var(--stagger)*10)}

/* --- 3. SHARED SUCCESS LANGUAGE ---------------------------------------
   One vocabulary for every "it worked": newsletter, contact / partner /
   wholesale submit, NotifyStock, address saved, settings saved.
   Icon pops in, copy rises behind it.                                    */
.contact-sent-ic,.auth-sent-ic,.pd-notify--done .pd-notify-ic,.ah-ok-ic{animation:ahPop var(--dur-base) var(--ease-out)}
.contact-sent>*,.auth-sent>*,.ah-ok>*{animation:ahRise var(--dur-calm) var(--ease-out) backwards}
.contact-sent>*:nth-child(2),.auth-sent>*:nth-child(2),.ah-ok>*:nth-child(2){animation-delay:var(--stagger)}
.contact-sent>*:nth-child(3),.auth-sent>*:nth-child(3),.ah-ok>*:nth-child(3){animation-delay:calc(var(--stagger)*2)}
.contact-sent>*:nth-child(n+4),.auth-sent>*:nth-child(n+4),.ah-ok>*:nth-child(n+4){animation-delay:calc(var(--stagger)*3)}
/* Inline "Saved ✓" confirmations (account settings). */
.acct-saved,.ah-ok-inline{animation:ahRise var(--dur-base) var(--ease-out)}

/* --- 4. SMALLER MOMENTS ----------------------------------------------- */
/* Dose selection settling in. */
.pd-dose-opt.on .pd-dose-badge{animation:ahSettle var(--dur-quick) var(--ease-out)}
/* Kit add-on tick. */
.pd-kit-check svg{transform:scale(.7);transition:opacity var(--dur-instant) var(--ease-out),transform var(--dur-quick) var(--ease-out)}
.pd-kit-item.on .pd-kit-check svg{transform:scale(1)}
/* CTA total + PDP price: the number updates, it doesn't jump. */
.pd-add-total,.pd-price-now{animation:ahNum var(--dur-base) var(--ease-out)}
/* Free-shipping threshold crossed — the bar completes, then the win line
   arrives with a single sheen pass. A small genuine win, marked quietly. */
.cart-progress-fill{transition:width var(--dur-calm) var(--ease-out)}
.cart-progress-line--win{animation:ahRise var(--dur-base) var(--ease-out)}
.cart-win-check{display:inline-block;animation:ahPop var(--dur-base) var(--ease-out) 80ms backwards}
.cart-progress-track{position:relative;overflow:hidden}
.cart-progress-track.is-complete::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.55),transparent);
  animation:ahSheen 620ms var(--ease-inout) 120ms;
}

/* --- 5. REDUCED MOTION ------------------------------------------------
   Accessibility standard, specified rather than left to the developer.
   Every animation above becomes an instant state change: the confirmation
   still HAPPENS and is still visible — it just doesn't move.             */
@media (prefers-reduced-motion:reduce){
  .icon-btn.ah-pulse svg,.cart-count,.cart-item--new,.cart-price,.cart-step-num,
  .oc-check,.oc-hero>*,.oc-grid>*,
  .contact-sent-ic,.auth-sent-ic,.pd-notify--done .pd-notify-ic,.ah-ok-ic,
  .contact-sent>*,.auth-sent>*,.ah-ok>*,.acct-saved,.ah-ok-inline,
  .pd-dose-opt.on .pd-dose-badge,.pd-add-total,.pd-price-now,
  .cart-progress-line--win,.cart-win-check{animation:none!important}
  .oc-check svg path{stroke-dashoffset:0;animation:none!important}
  .cart-progress-fill{transition:none!important}
  .cart-progress-track.is-complete::after{display:none}
  .btn.is-added::after{animation:none!important}
  .pd-kit-check svg{transition:none!important;transform:none!important}
  .ah-fly{display:none!important}   /* fly-to-cart never runs */
}

/* The entry gate's backdrop fade (polish.css `gateFade`) is an entrance animation, and TOKENS.md
   requires a reduced-motion fallback for EVERY animation — entrances become near-instant. The gate
   still appears; it just does not move. */
@media (prefers-reduced-motion: reduce) {
  .gate-backdrop { animation: none !important; }
}

/* The announcement marquee is a decorative infinite loop. TOKENS.md: under
   prefers-reduced-motion "all decorative loops disabled" — the messages stay
   readable, they just stop moving. BEHAVIORS lists the marquee as "paused under
   reduced motion" explicitly. */
@media (prefers-reduced-motion: reduce) {
  .announce-track,
  .announce-marquee .announce-track,
  [class*="announce"] [class*="track"] { animation: none !important; }

  /*
   * Stopping the loop is correct — but stopping it ALONE looked broken, and that is what a real
   * phone with iOS "Reduce Motion" was reporting as "the marquee doesn't work".
   *
   * The track is three copies of the message list on one nowrap line inside `overflow: hidden`, so
   * freezing it at translateX(0) leaves the first copy cut off mid-sentence at the right edge, with
   * the fade gradients over both ends implying movement that never comes. A cut-off strip that
   * hints at motion reads as a bug; a complete one reads as a design.
   *
   * So under reduced motion it becomes a STATIC, COMPLETE strip: one copy of the messages, centred
   * when they fit, and swipeable when they do not, so every message is still reachable. The fades
   * go, because there is nothing scrolling past for them to soften.
   */
  .announce-marquee {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }
  .announce-marquee::-webkit-scrollbar { display: none; }
  .announce-marquee::before,
  .announce-marquee::after { display: none; }

  .announce-track {
    padding-left: 0;
    justify-content: center;
    min-width: 100%;
    /* Copies 2 and 3 exist only to make the loop seamless; with no loop they are just repetition,
       and they are marked as duplicates in header.php rather than counted here — a positional
       `nth-child` rule would silently break the moment a message is added or removed. */
  }
  .announce-track > .announce-item--dup { display: none; }
}
