/* Mandala Medicine motion + swipe (Wren, 2026-09-28). Loads last, after
   core/assets/motion.css, style.css and inner.css, so the theme has the final
   word on its own choreography.

   The rule underneath all of it is the engine's: MOTION NEVER GATES CONTENT.
   Every hidden state here is scoped to html.fx (dropped by the engine when
   motion.js never reports in, under reduced motion, and on ?nofx=1), every
   class that hides something is added by script (mm-motion.js), and the hero
   is plain CSS animation, which always finishes on its own. The resting
   state of every rule below IS the final frame, so reduced motion, print,
   the inline editor and a reader with scripts off all see the same page. */

/* ---------- scroll reveal (the engine's .fade, tuned) ---------- */
/* mm-motion.js adds .fade only to blocks below the fold at load; the engine
   observes them and keeps its sweep and 6 s backstop */
html.fx main .fade:not(.in){transform:translateY(16px)}
html.fx main .fade{transition-duration:.62s,.62s;transition-timing-function:cubic-bezier(.2,.65,.25,1)}
/* in a row that really scrolls sideways the cards slide in from the side
   instead (.sw-on is set by script only while the row is a scroller, so a
   row that is a plain grid at this width never pushes past the page edge) */
html.fx main [data-swipe].sw-on>.fade:not(.in){transform:translateX(28px)}

/* ---------- images arrive when their bytes do ---------- */
/* .mm-ld is added by script to an image that has not loaded yet; it fades
   in on decode. While it waits, its frame shows paper, not a hole. */
html.fx img.mm-ld{opacity:0}
html.fx img.mm-ld.mm-in{opacity:1;transition:opacity .6s cubic-bezier(.2,.6,.2,1)}
html.fx :not(a):has(>img.mm-ld){background-color:var(--paper)}
html.fx .hero-photo:has(>img.mm-ld){background-color:var(--olive-2)}
.clinic-photo,.clinic-old,.svc-photo,.post-hero,.person-photo,.fig{background-color:var(--paper)}

/* ---------- home hero: the opening, about 3.8 s, then it rests ---------- */
/*  0.00  the photo starts a slow push-in (to 104.5%, where it stays)
    0.30  the photo fades in and rises into place
    0.05  eyebrow rises
    0.18  the headline rises line by line (words carry --wd, their whole delay,
          from the inline script in home.php; without it the headline rises whole)
    0.75  the line under it, then the buttons
    1.40  a sage highlight draws under "healing", glows once, and settles
          into a hairline underline
    3.80  rest                                                           */
.hero-photo{position:relative;isolation:isolate}
.hero-photo img{transform:scale(1.045);transform-origin:44% 46%}
.hero h1 .w{display:inline-block}
.hero .w-hl{position:relative;isolation:isolate}
.hero .w-hl::before{content:"";position:absolute;left:-.04em;right:-.04em;bottom:.04em;height:.36em;border-radius:.1em;background:rgba(95,139,115,.7);z-index:-1;transform-origin:0 100%;transform:scaleX(1) scaleY(.12);pointer-events:none}

html.fx .hero-photo{animation:mmRise .9s cubic-bezier(.2,.65,.25,1) .3s both}
html.fx .hero-photo img{animation:mmPush 3.8s cubic-bezier(.25,.1,.25,1) both}
html.fx .hero .eyebrow{animation:mmRise .62s cubic-bezier(.2,.65,.25,1) .05s both}
html.fx .hero h1{animation:mmRise .7s cubic-bezier(.2,.65,.25,1) .18s both}
html.fx .hero h1.mm-split{animation:none}
html.fx .hero h1.mm-split .w{animation:mmWord .7s cubic-bezier(.2,.65,.25,1) var(--wd,.18s) both}
html.fx .hero h1.mm-split .w-hl{animation:mmWord .7s cubic-bezier(.2,.65,.25,1) var(--wd,.18s) both,mmGlow 1.5s ease-in-out 1.7s both}
html.fx .hero .w-hl::before{animation:mmBand 1.7s cubic-bezier(.3,.6,.2,1) 1.4s both}
html.fx .hero-sub{animation:mmRise .65s cubic-bezier(.2,.65,.25,1) .75s both}
html.fx .hero .actions{animation:mmRise .65s cubic-bezier(.2,.65,.25,1) .9s both}
/* a hidden tab holds the opening until the reader is looking */
.hero.mm-hold *,.hero.mm-hold *::before,.hero.mm-hold *::after{animation-play-state:paused!important}

@keyframes mmPush{from{transform:scale(1)}to{transform:scale(1.045)}}
@keyframes mmRise{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}
@keyframes mmWord{from{opacity:0;transform:translateY(.4em)}to{opacity:1;transform:none}}
@keyframes mmBand{0%{transform:scaleX(0) scaleY(1)}45%{transform:scaleX(1) scaleY(1)}68%{transform:scaleX(1) scaleY(1)}100%{transform:scaleX(1) scaleY(.12)}}
@keyframes mmGlow{0%,100%{text-shadow:0 0 0 rgba(249,246,238,0)}50%{text-shadow:0 0 .3em rgba(249,246,238,.42)}}

/* ---------- swipe rows ---------- */
/* Rows marked data-swipe become one sideways, snapping row with the next
   card peeking in: "599" on phones, "920" up to the menu breakpoint, "all"
   at every width. Plain CSS, so the swipe works with no script at all;
   mm-motion.js adds mouse drag and, for "all", the arrow buttons. The row
   bleeds to the screen edge inside .wrap, which is exactly the padding it
   takes back, so the page itself never scrolls sideways. */
[data-swipe]::-webkit-scrollbar{display:none}
@media (max-width:599px){
  [data-swipe]{display:grid;grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:var(--sw-w,78%);gap:12px;
    overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;scroll-padding-left:var(--pad);scroll-padding-right:var(--pad);scroll-padding-inline:var(--pad);
    margin-left:calc(var(--pad) * -1);margin-right:calc(var(--pad) * -1);margin-inline:calc(var(--pad) * -1);padding-inline:var(--pad);scrollbar-width:none;-webkit-overflow-scrolling:touch}
  [data-swipe]>*{scroll-snap-align:start;min-width:0}
  .space-grid[data-swipe]{--sw-w:80%}
  .owners-pair[data-swipe]{--sw-w:74%}
  .cards[data-swipe]{--sw-w:72%;gap:16px}
  .pgrid[data-swipe]{--sw-w:62%;gap:14px}
  .bgrid[data-swipe]{--sw-w:84%;gap:16px}
}
@media (min-width:600px) and (max-width:920px){
  [data-swipe="920"],[data-swipe="all"]{display:grid;grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:var(--sw-w,44%);gap:14px;
    overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;scroll-padding-left:var(--pad);scroll-padding-right:var(--pad);scroll-padding-inline:var(--pad);
    margin-left:calc(var(--pad) * -1);margin-right:calc(var(--pad) * -1);margin-inline:calc(var(--pad) * -1);padding-inline:var(--pad);scrollbar-width:none;-webkit-overflow-scrolling:touch}
  [data-swipe="920"]>*,[data-swipe="all"]>*{scroll-snap-align:start;min-width:0}
  .space-grid[data-swipe]{--sw-w:46%}
  .cards[data-swipe]{--sw-w:40%;gap:20px}
}
/* the room photos all take one shape in a row, so the row has one height */
@media (max-width:920px){
  .space-grid[data-swipe]>figure{aspect-ratio:4/5;grid-column:auto}
}
@media (min-width:921px){
  [data-swipe="all"]{display:grid;grid-template-columns:none;grid-auto-flow:column;grid-auto-columns:calc((100% - 4 * 24px) / 4.3);gap:24px;
    overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;scrollbar-width:none;
    /* the row runs on past the right edge of the column to the edge of the
       screen, so the next card is cut by the window, not by a margin */
    margin-right:calc(50% - 50vw);padding-right:calc(50vw - 50%)}
  [data-swipe="all"]>*{scroll-snap-align:start;min-width:0}
}
/* the inline editor's pencils sit 8px outside their host and a scrolling row
   would clip them; editor.css moves those pencils inside the card instead, so
   a signed-in editor sees the row at exactly the public height (2026-10-05) */

/* mouse drag (mm-motion.js adds .sw-on only to a row that really overflows) */
@media (hover:hover) and (pointer:fine){[data-swipe].sw-on{cursor:grab}}
[data-swipe].is-drag{cursor:grabbing;scroll-snap-type:none;scroll-behavior:auto;-webkit-user-select:none;user-select:none}
[data-swipe] img{-webkit-user-drag:none}

/* the arrows: 44px, mouse screens only, in the section head's right edge
   (absolutely placed, so arriving late moves nothing) */
.team .sec-head{position:relative;padding-right:112px}
.sw-ctl{position:absolute;right:0;bottom:0;display:none;gap:8px}
@media (hover:hover) and (pointer:fine){.sw-ctl.on{display:flex}}
.sw-btn{display:grid;place-items:center;width:44px;height:44px;padding:0;border:1px solid var(--line-strong);border-radius:50%;background:transparent;color:var(--olive);cursor:pointer;transition:border-color .2s,opacity .2s}
.sw-btn::before{content:"";width:8px;height:8px;border-top:1.5px solid currentColor;border-right:1.5px solid currentColor;transform:translateX(-2px) rotate(45deg)}
.sw-prev::before{transform:translateX(2px) rotate(-135deg)}
.sw-btn:hover:not(:disabled){border-color:var(--olive)}
.sw-btn:disabled{opacity:.32;cursor:default}

/* ---------- the three ways out ---------- */
@media (prefers-reduced-motion:reduce){
  .hero *,.hero *::before,.hero *::after{animation:none!important}
  [data-swipe]{scroll-behavior:auto}
}
@media print{
  html.fx .fade,html.fx .reveal,html.fx img.mm-ld{opacity:1!important;transform:none!important;transition:none!important}
  .hero *,.hero *::before,.hero *::after{animation:none!important}
  [data-swipe]{display:grid!important;grid-auto-flow:row!important;grid-template-columns:repeat(2,minmax(0,1fr))!important;overflow:visible!important;margin-left:0!important;margin-right:0!important;margin-inline:0!important;padding-left:0!important;padding-right:0!important;padding-inline:0!important}
  .sw-ctl{display:none!important}
}
.no-fx .hero *,.no-fx .hero *::before,.no-fx .hero *::after{animation:none!important}
