/* ============================================================================
   BATWANA — motion system ("Setup Day"), phases 1 and 2 of the motion spec.
   Rules: transform and opacity only (FAQ height is the one sanctioned
   exception); content is visible wherever a feature is unsupported; every
   duration collapses under prefers-reduced-motion.
   ========================================================================= */

/* ---------- tokens ---------- */
:root{
  --dur-instant:90ms; --dur-quick:160ms; --dur-base:240ms; --dur-scenic:480ms; --stagger:60ms;

  --ease-standard:cubic-bezier(.2,0,0,1);
  --ease-decel:cubic-bezier(.05,.7,.1,1);
  --ease-exit:cubic-bezier(.3,0,.8,.15);
  --ease-overshoot:cubic-bezier(.34,1.4,.64,1);

  /* Fallbacks first; real springs below where linear() is supported. */
  --spring-snappy:var(--ease-standard);  --spring-snappy-dur:320ms;
  --spring-bouncy:var(--ease-overshoot); --spring-bouncy-dur:520ms;
  --spring-gentle:var(--ease-decel);     --spring-gentle-dur:600ms;

  --press:.96; --press-deep:.88; --lift:-6px; --tilt-max:3deg;
}
@supports (animation-timing-function: linear(0, 1)){
  :root{
    --spring-snappy:linear(0, .054, .159, .301, .447, .57, .688, .785, .854, .912, .954, .98, .999, 1.01, 1.015, 1.017, 1.017, 1.015, 1.013, 1.01, 1.008, 1.006, 1.004, 1.003, 1.002, 1.001, 1, 1, 1);
    --spring-snappy-dur:450ms;
    --spring-bouncy:linear(0, .154, .455, .785, 1.026, 1.168, 1.205, 1.174, 1.109, 1.045, .993, .965, .958, .965, .978, .991, 1.002, 1.007, 1.009, 1.007, 1.005, 1.002, 1, .999, .998, .999, .999, 1, 1);
    --spring-bouncy-dur:900ms;
    --spring-gentle:linear(0, .052, .153, .279, .397, .512, .611, .689, .758, .81, .854, .888, .914, .935, .951, .962, .972, .978, .984, .988, .991, .993, .995, .996, .997, .998, .998, .999, 1);
    --spring-gentle-dur:730ms;
  }
}

/* ---------- type ---------- */
h1,h2,h3{text-wrap:balance}
p,li,dd{text-wrap:pretty}

/* ---------- touch targets: 48px minimum ---------- */
.btn--sm{min-height:48px}
.iconbtn{width:48px;height:48px}
.links a,.ftr li a,.faq summary{min-height:48px}
.links a{min-width:48px;justify-content:center}
/* footer links reach 48px wide without moving: the padding is cancelled by the margin */
.ftr li a{min-width:48px;padding-inline:8px;margin-inline:-8px}
/* primary actions are 56px tall on phones */
@media(max-width:699px){ .btn,.btn--sm{min-height:56px} }

/* ---------- focus: the indigo halo grows in; the outline itself is never late ---------- */
:where(a,button,summary,[tabindex]){transition:box-shadow var(--spring-snappy-dur) var(--spring-snappy)}

/* ---------- press: squish within a frame, spring back on release ---------- */
.btn,.iconbtn{
  -webkit-tap-highlight-color:transparent;touch-action:manipulation;
  transition:transform var(--spring-snappy-dur) var(--spring-snappy),background-color var(--dur-quick) var(--ease-standard),
             box-shadow var(--spring-snappy-dur) var(--spring-snappy)
}
.btn:active{transform:scale(var(--press))}
.iconbtn:active{transform:scale(var(--press-deep))}
.btn:active,.iconbtn:active{transition-duration:var(--dur-instant),var(--dur-quick),var(--spring-snappy-dur);transition-timing-function:var(--ease-standard)}

/* ---------- header: progress line, active-section pill, condensing logo ---------- */
.progress{
  position:absolute;left:0;right:0;bottom:0;height:3px;background:var(--yellow);
  transform-origin:0 50%;transform:scaleX(0);pointer-events:none
}
@supports (animation-timeline: scroll()){
  .progress{animation:m-grow linear both;animation-timeline:scroll(root)}
}
@supports not (animation-timeline: scroll()){ .progress{display:none} }
@keyframes m-grow{to{transform:scaleX(1)}}

.links{position:relative}
.links .pill{
  position:absolute;left:0;bottom:4px;width:40px;height:4px;border-radius:2px;background:var(--yellow);
  transform-origin:0 50%;opacity:0;pointer-events:none;
  transition:transform var(--spring-snappy-dur) var(--spring-snappy),opacity var(--dur-quick) var(--ease-standard)
}
.links[data-pill] .pill{opacity:1}
.links a[data-active]:hover{text-decoration:none}

.brand img{transform-origin:0 50%;transition:transform var(--dur-base) var(--ease-standard)}
.hdr.stuck .brand img{transform:scale(.86)}

/* ---------- hero: "the splat lands" (first visit per session, .play) ----------
   One focal anchor at a time: the photo holds still, the copy leads as one cascade (eyebrow ->
   words -> lead -> chips -> CTA), and the splat lands last, on its own, once the CTA has settled (700 ms + 900 ms).
   The whole entrance is over by 2.5 s. */
.hero__media{overflow:hidden}
.hero__copy{isolation:isolate}
.hero__splat{
  position:absolute;z-index:-1;top:0;left:-34px;width:min(78vw,300px);height:auto;
  color:var(--amber);opacity:.2;pointer-events:none;transform-origin:30% 60%
}
@media(min-width:1000px){
  .hero__splat{top:calc(var(--header-h) - 8px);left:calc(max(var(--gutter),(100vw - var(--max)) / 2) - 72px);width:min(36vw,460px)}
}
.hero__copy .confetti{z-index:-1}
.hero h1 .w{display:inline-block;transform-origin:50% 100%}

.hero.play .hero__splat{animation:m-splat var(--spring-bouncy-dur) var(--spring-bouncy) 1600ms backwards}
.hero.play .eyebrow{--y:8px;animation:m-up var(--dur-base) var(--ease-standard) 80ms backwards}
.hero.play h1 .w{animation:m-word var(--spring-snappy-dur) var(--spring-snappy) backwards;animation-delay:calc(160ms + var(--i,0) * var(--stagger))}
.hero h1 .w:nth-child(2){--i:1} .hero h1 .w:nth-child(3){--i:2} .hero h1 .w:nth-child(4){--i:3}
.hero h1 .w:nth-child(5){--i:4} .hero h1 .w:nth-child(6){--i:5} .hero h1 .w:nth-child(7){--i:6}
.hero.pre .hero__copy>:not(.hero__splat):not(.confetti){opacity:0}
.hero.play .hero__lead{--y:10px;animation:m-up var(--dur-base) var(--ease-standard) 440ms backwards}
.hero.play .hero__chips li{transform-origin:50% 100%;animation:m-inflate var(--spring-bouncy-dur) var(--spring-bouncy) backwards;animation-delay:calc(520ms + var(--i,0) * var(--stagger))}
.hero__chips li:nth-child(2){--i:1}
.hero.play .hero__proof{animation:m-fade var(--dur-base) var(--ease-standard) 840ms backwards}
.hero.play .hero__cta .btn{transform-origin:50% 100%;animation:m-inflate var(--spring-bouncy-dur) var(--spring-bouncy) 700ms backwards}
.hero.play .hero__link{animation:m-fade var(--dur-quick) var(--ease-standard) 780ms backwards}

@keyframes m-splat{from{transform:scale(0) rotate(-20deg)}}
@keyframes m-up{from{opacity:0;transform:translateY(var(--y,8px))}}
@keyframes m-word{from{opacity:0;transform:translateY(.5em) scaleY(.92)}}
@keyframes m-inflate{from{opacity:0;transform:scale(.6)}}
@keyframes m-fade{from{opacity:0}}

/* ---------- menu sheet: springs up from the bar, chips stagger, leaves faster than it came ---------- */
.drawer__bg{animation:m-fade var(--dur-base) var(--ease-standard) backwards}
/* the shadow covers the strip the spring's overshoot would otherwise uncover at the bottom */
.drawer__panel{box-shadow:0 24px 0 var(--indigo-900);animation:m-panel var(--spring-snappy-dur) var(--spring-snappy) backwards}
.drawer nav a{animation:m-slide var(--dur-base) var(--ease-decel) backwards;animation-delay:calc(80ms + var(--i,0) * 40ms)}
.drawer[data-closing] .drawer__bg{animation:m-out var(--dur-quick) var(--ease-exit) forwards}
.drawer[data-closing] .drawer__panel{animation:m-panel-out var(--dur-quick) var(--ease-exit) forwards}
@keyframes m-panel{from{transform:translateY(100%)}}
@keyframes m-panel-out{to{transform:translateY(100%)}}
@keyframes m-slide{from{opacity:0;transform:translateY(12px)}}
@keyframes m-out{to{opacity:0}}

/* ---------- mobile header: the section label flips, the dots fill ---------- */
.hdr__label span{animation:m-label-in var(--spring-snappy-dur) var(--spring-snappy) backwards}
.hdr__label span.out{animation:m-label-out var(--dur-quick) var(--ease-exit) forwards}
@keyframes m-label-in{from{opacity:0;transform:translateY(60%)}}
@keyframes m-label-out{to{opacity:0;transform:translateY(-60%)}}
.hdr__dots i{transition:background-color var(--dur-quick) var(--ease-standard)}
.hdr__dots i[data-now]{animation:m-dot var(--spring-snappy-dur) var(--spring-snappy)}
@keyframes m-dot{50%{transform:scale(1.4)}}

/* ---------- arrival: after a jump, the section's eyebrow gets a one-shot swipe ---------- */
.eyebrow{width:fit-content;position:relative}
@media (prefers-reduced-motion: no-preference){
  .eyebrow.arrive::after{
    content:"";position:absolute;left:0;right:0;bottom:-3px;height:3px;border-radius:2px;background:var(--yellow);
    transform-origin:0 50%;
    animation:m-swipe var(--spring-snappy-dur) var(--spring-snappy) backwards,m-out var(--dur-quick) var(--ease-exit) 1.2s forwards
  }
}
@keyframes m-swipe{from{transform:scaleX(0)}}

/* the hero CTA's magnetic lean uses `translate`, so it never fights the press scale */
.hero__cta .btn{transition:transform var(--spring-bouncy-dur) var(--spring-bouncy),background-color var(--dur-quick) var(--ease-standard),
  box-shadow var(--spring-snappy-dur) var(--spring-snappy),translate var(--spring-snappy-dur) var(--spring-snappy)}

/* ---------- package sheet: springs up; with View Transitions the card itself morphs into its head ---------- */
.pkg-sheet[open]:not(.vt){animation:m-panel var(--spring-snappy-dur) var(--spring-snappy)}
.pkg-sheet[open]:not(.vt)::backdrop{animation:m-fade var(--dur-base) var(--ease-standard)}
.pkg-sheet .ticks li{animation:m-up var(--dur-base) var(--ease-decel) backwards;animation-delay:calc(120ms + var(--i,0) * 40ms)}
/* title and price glide from the card to the sheet head; the old copies are hidden, so nothing
   double-exposes mid-flight. 300ms: short enough that the page is never unresponsive for long. */
::view-transition-group(pkg-title),::view-transition-group(pkg-price){animation-duration:300ms;animation-timing-function:var(--spring-snappy)}
::view-transition-old(pkg-title),::view-transition-old(pkg-price){animation:none;opacity:0}
::view-transition-new(pkg-title),::view-transition-new(pkg-price){animation:none;height:100%;object-fit:none}
/* No full-page snapshot: capturing the root costs hundreds of ms on a budget phone. Only the title
   and price are captured; the sheet itself fades in live underneath them. */
:root{view-transition-name:none}
.pkg-sheet.vt[open]{animation:m-fade 200ms var(--ease-standard)}
.pkg-sheet.vt[open]::backdrop{animation:m-fade 200ms var(--ease-standard)}
@media (prefers-reduced-motion: reduce){ ::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation-duration:1ms} }

/* ---------- sticky bar: waits for the hero to leave, then inflates once ---------- */
.bar[data-wait]{transform:translateY(130%)}
.bar.pop{transform-origin:50% 100%;animation:m-bar calc(var(--spring-bouncy-dur) * .72) cubic-bezier(.2,0,0,1)}
/* Poisson: matter squashes on the opposing axis on its way to rest (area held within ~2%) */
@keyframes m-bar{0%{transform:translateY(130%) scale(.9)}60%{transform:translateY(-4%) scale(1.03,.96)}82%{transform:translateY(1%) scale(.99,1.01)}100%{transform:none}}

/* ---------- FAQ: smooth height where the browser can, snap where it can't ---------- */
.faq summary::after,.fold summary::after{transition:transform var(--spring-snappy-dur) var(--spring-snappy)}
.faq details[open] p,.fold[open]>.scroller{--y:4px;animation:m-up var(--dur-base) var(--ease-decel) backwards}
@supports (interpolate-size: allow-keywords){
  .faq,.fold{interpolate-size:allow-keywords}
  .fold::details-content{
    block-size:0;overflow:hidden;
    transition:block-size var(--dur-base) var(--ease-standard),content-visibility var(--dur-base) allow-discrete
  }
  .fold[open]::details-content{block-size:auto}
  .faq details::details-content{
    block-size:0;overflow:hidden;
    transition:block-size var(--dur-base) var(--ease-standard),content-visibility var(--dur-base) allow-discrete
  }
  .faq details[open]::details-content{block-size:auto}
}

/* ---------- package cards: lift, tilt toward the pointer, stamp ---------- */
#hire .g3{perspective:900px}
.pkg{position:relative;contain:layout;transition:transform var(--spring-snappy-dur) var(--spring-snappy)}
/* the deeper shadow is a pre-rendered layer that only fades: box-shadow never animates */
.pkg::after{
  content:"";position:absolute;inset:-2px;border-radius:inherit;box-shadow:var(--e3);
  opacity:0;pointer-events:none;transition:opacity var(--dur-base) var(--ease-standard)
}
.pkg:has(:focus-visible){transform:translateY(var(--lift))}
.pkg:has(:focus-visible)::after{opacity:1}
@media (pointer: fine){ .pkg:hover::after{opacity:1} }
.tag{transform:rotate(-4deg)}
.tag--wait{opacity:0}
.tag--in{animation:m-stamp calc(var(--spring-bouncy-dur) * .72) cubic-bezier(.2,0,0,1) backwards}
@keyframes m-stamp{0%{opacity:0;transform:scale(1.6) rotate(-14deg)}55%{opacity:1;transform:scale(.92,1.06) rotate(-3deg)}78%{transform:scale(1.03,.98) rotate(-4.5deg)}100%{transform:rotate(-4deg)}}

/* ---------- booking CTAs: squash on press, stretch through to rest ---------- */
.btn--wa,[data-cta="book"]{transition:transform var(--spring-bouncy-dur) var(--spring-bouncy),background-color var(--dur-quick) var(--ease-standard),box-shadow var(--spring-snappy-dur) var(--spring-snappy)}
.btn--wa:active,[data-cta="book"]:active{transform:scale(var(--press))}
@media (prefers-reduced-motion: no-preference){
  .btn--wa:active,[data-cta="book"]:active{transform:scaleX(1.06) scaleY(.9)}
}
.splat-particle{
  position:fixed;width:12px;height:12px;z-index:500;pointer-events:none;
  -webkit-mask:url(splat/splat-pink.svg) center/contain no-repeat;mask:url(splat/splat-pink.svg) center/contain no-repeat
}

/* ---------- occasion tiles: splat cards ---------- */
.tile{contain:layout paint;transition:background-color var(--dur-quick) var(--ease-standard),transform var(--spring-snappy-dur) var(--spring-snappy)}
.tile:active{transform:scale(.97);transition-duration:var(--dur-quick),var(--dur-instant);transition-timing-function:var(--ease-standard)}
.tile::before{transition:transform var(--spring-bouncy-dur) var(--spring-bouncy)}
.tile:hover::before,.tile:focus-visible::before{transform:scale(1.12) rotate(8deg)}
@supports ((mask-image:url("x.svg")) or (-webkit-mask-image:url("x.svg"))){
  .tile::before{
    border-radius:0;width:170px;height:170px;
    -webkit-mask:url(splat/splat-amber.svg) center/contain no-repeat;mask:url(splat/splat-amber.svg) center/contain no-repeat
  }
  .tile:nth-child(4n+2)::before{-webkit-mask-image:url(splat/splat-green.svg);mask-image:url(splat/splat-green.svg)}
  .tile:nth-child(4n+3)::before{-webkit-mask-image:url(splat/splat-pink.svg);mask-image:url(splat/splat-pink.svg)}
  .tile:nth-child(4n+4)::before{-webkit-mask-image:url(splat/splat-red.svg);mask-image:url(splat/splat-red.svg)}
}

/* ---------- scroll reveals: hidden start states exist only where they can animate ---------- */
@supports (animation-timeline: view()){
  @media (prefers-reduced-motion: no-preference){
    .reveal{animation:m-reveal linear backwards;animation-timeline:view();animation-range:entry 0% entry 50%}
    @keyframes m-reveal{from{opacity:0;transform:translateY(24px) scale(.98)}}
    /* tiles stagger by column: later columns start a little further into the range */
    .tile{animation:m-tile linear backwards;animation-timeline:view();animation-range:entry calc(var(--col,0) * 6%) entry calc(40% + var(--col,0) * 6%)}
    @media(min-width:700px){ .tile:nth-child(even){--col:1} }
    @media(min-width:1000px){ .tile:nth-child(3n+2){--col:1} .tile:nth-child(3n){--col:2} .tile:nth-child(3n+1){--col:0} }
    @keyframes m-tile{from{opacity:0;transform:translateY(24px) scale(.96)}}
    /* the bunting dots drift; the wave itself stays put so the seam never opens */
    .divider{view-timeline:--divider}
    .divider circle{transform-box:fill-box;animation:m-drift linear both;animation-timeline:--divider}
    @keyframes m-drift{from{transform:translateY(10px)}to{transform:translateY(-20px)}}
  }
}

/* ---------- G2 corners: a native superellipse where supported, today's radii elsewhere ---------- */
@supports (corner-shape: squircle){
  .card,.fold,.tile,.faq details,.hero__chips li,.pkg__open,.pkg-sheet,.drawer__panel,.drawer nav a,
  .contact-row a,.contact-row div{corner-shape:squircle}
  /* a squircle reads ~15% tighter than a circular arc of the same radius: compensate */
  .card,.fold,.tile,.faq details{border-radius:calc(var(--r-card) * 1.15)}
  .hero__chips li,.pkg__open,.drawer nav a{border-radius:18px}
}

/* ---------- specular party lights: a soft band of light slides across the primary CTA, the
   stamp and the hero chips, opposite to the cursor (desktop) or the phone's tilt (Party mode),
   as if a stage light hung above the screen. One layer each, transform and opacity only. ---------- */
.hero__cta .btn,.tag,.hero__chips li{position:relative;overflow:hidden}
.hero__cta .btn::after,.tag::after,.hero__chips li::after{
  content:"";position:absolute;top:0;bottom:0;left:-100%;width:300%;pointer-events:none;
  background:linear-gradient(105deg,transparent 42%,rgba(255,255,255,.38) 50%,transparent 58%);
  transform:translateX(var(--sheen-x,-34%));opacity:var(--sheen-o,0);
  transition:opacity var(--dur-base) var(--ease-standard)
}
@media (prefers-reduced-motion: reduce){ .hero__cta .btn::after,.tag::after,.hero__chips li::after{display:none} }

/* ---------- reduced motion: every state still changes, instantly ---------- */
@media (prefers-reduced-motion: reduce){
  :root{
    --dur-quick:1ms; --dur-base:1ms; --dur-scenic:1ms; --stagger:0ms;
    --spring-snappy-dur:1ms; --spring-bouncy-dur:1ms; --spring-gentle-dur:1ms;
    --press:1; --press-deep:1; --lift:0px; --tilt-max:0deg;
  }
  *,*::before,*::after{animation-delay:0s!important;transition-delay:0s!important}
}

/* ---------- one bar of signal: the offline / back-online pill (motion.js) ---------- */
.signal{position:fixed;z-index:60;left:50%;top:calc(var(--header-h,64px) + 8px);margin:0;max-width:calc(100vw - 32px);
  padding:8px 16px;border-radius:999px;background:var(--indigo-900,#2A2266);color:#fff;font-size:.9rem;font-weight:600;
  box-shadow:0 2px 4px rgba(42,34,102,.06),0 12px 28px rgba(42,34,102,.12);
  transform:translate(-50%,-160%);opacity:0;pointer-events:none;
  transition:transform var(--spring-snappy-dur) var(--spring-snappy),opacity var(--dur-quick) var(--ease-standard)}
.signal--off{background:#7A1033}
.signal.show{transform:translate(-50%,0);opacity:1}
