/* ============================================================
   flow.css - Vail Digital motion layer
   Shared by every page. Motion primitives only.
   Pairs with /assets/flow.js. Everything degrades to
   "visible and static" if flow.js never runs.

   CACHE
   -----
   Every page links this file with ?v=<date>. After editing it, bump that
   query on ALL pages or returning visitors keep the old copy until their
   cache expires. Current: v=20260915c

     python3 - <<'EOF'
     import re, glob
     V = 'YYYYMMDD'
     p = re.compile(r'((?:href|src)=")(/assets/(?:flow|splash)\.(?:css|js))(\?v=[^"]*)?(")')
     for f in glob.glob('*.html'):
         s = open(f).read()
         open(f, 'w').write(p.sub(lambda m: m.group(1) + m.group(2) + '?v=' + V + m.group(4), s))
     EOF

   ============================================================ */

:root{
  --flow-ease: cubic-bezier(.16,.84,.28,1);
  --flow-ease-out: cubic-bezier(.22,1,.36,1);
  --flow-dur: .82s;
  --flow-dur-slow: 1.15s;
}

/* ---------- 1. REVEALS ----------
   Visible by default. flow.js adds .flow-ready to <html>, which
   is what arms the hidden state - so a script failure or a
   crawler always sees the finished page. */
.flow-ready [data-flow]{
  opacity:0;
  will-change:opacity,transform;
  transition:
    opacity var(--flow-dur) var(--flow-ease),
    transform var(--flow-dur) var(--flow-ease),
    filter var(--flow-dur) var(--flow-ease);
  transition-delay:var(--flow-delay,0ms);
}
.flow-ready [data-flow="up"]{transform:translate3d(0,34px,0)}
.flow-ready [data-flow="rise"]{transform:translate3d(0,72px,0);transition-duration:var(--flow-dur-slow)}
.flow-ready [data-flow="fade"]{transform:none}
.flow-ready [data-flow="scale"]{transform:scale(.94)}
.flow-ready [data-flow="left"]{transform:translate3d(-40px,0,0)}
.flow-ready [data-flow="right"]{transform:translate3d(40px,0,0)}
.flow-ready [data-flow="blur"]{filter:blur(14px);transform:translate3d(0,20px,0)}
.flow-ready [data-flow].is-in{opacity:1;transform:none;filter:none}

/* Line-by-line headline reveal */
.flow-line{display:block;overflow:hidden;padding-block:.04em}
.flow-line > span{
  display:block;
  transform:translate3d(0,105%,0);
  transition:transform var(--flow-dur-slow) var(--flow-ease-out);
  transition-delay:var(--flow-delay,0ms);
}
.flow-ready [data-flow-lines].is-in .flow-line > span{transform:none}
html:not(.flow-ready) .flow-line > span{transform:none}

/* ---------- 2. SCRUBBED ELEMENTS ----------
   flow.js writes --flow-p (0 to 1) as the element crosses. */
[data-flow-scrub]{--flow-p:0}
[data-flow-scrub="drift"]{transform:translate3d(0,calc((1 - var(--flow-p)) * 48px),0)}
[data-flow-scrub="settle"]{
  opacity:calc(.25 + var(--flow-p) * .75);
  letter-spacing:calc(.06em - var(--flow-p) * .06em);
}
[data-flow-scrub="parallax"]{transform:translate3d(0,calc(var(--flow-p) * -64px),0)}
[data-flow-scrub="grow"]{transform:scale(calc(.9 + var(--flow-p) * .1))}

/* ---------- 3. MOOD ----------
   One fixed layer, cross-faded per section. Sits at z-index -1
   so it stays behind the existing #bg-canvas / .gradient-orb /
   .particle layers, which are all fixed at z-index 0. */
.flow-mood{
  position:fixed;inset:0;z-index:0;pointer-events:none;
  background:var(--flow-mood-a,transparent);
  transition:background 1.1s var(--flow-ease);
}
.flow-mood__orb{
  position:absolute;border-radius:50%;filter:blur(90px);
  opacity:.5;transition:background 1.2s var(--flow-ease), opacity 1.2s var(--flow-ease);
}

/* ---------- 4. NARRATIVE ----------
   Sticky media, scrolling copy. */
.flow-narrative{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(32px,6vw,88px);
  align-items:start;
}
.flow-narrative__media{
  position:sticky;
  top:calc(50vh - min(29vh, 300px));
  height:min(58vh,600px);
  border-radius:18px;
  overflow:hidden;
  isolation:isolate;
}
.flow-narrative__panel{
  position:absolute;inset:0;opacity:0;transform:scale(1.03);
  transition:opacity .66s var(--flow-ease), transform .9s var(--flow-ease);
}
.flow-narrative__panel.is-active{opacity:1;transform:none}
.flow-narrative__panel > img,
.flow-narrative__panel > video{width:100%;height:100%;object-fit:cover;display:block}
html:not(.flow-ready) .flow-narrative__panel{position:relative;opacity:1;transform:none}
html:not(.flow-ready) .flow-narrative__media{position:static;height:auto}
.flow-narrative__steps{display:flex;flex-direction:column}
.flow-narrative__step{min-height:74vh;display:flex;flex-direction:column;justify-content:center}

@media (max-width:880px){
  .flow-narrative{grid-template-columns:1fr;gap:0}
  .flow-narrative__media{position:sticky;top:72px;height:42vh;margin-bottom:28px}
  .flow-narrative__step{min-height:0;padding-block:34px}
}

/* ---------- 5. PROGRESS RAIL ---------- */
.flow-rail{position:fixed;top:0;left:0;right:0;height:2px;z-index:1200;background:transparent;pointer-events:none}
.flow-rail__fill{
  height:100%;width:100%;transform-origin:0 50%;
  transform:scaleX(var(--flow-progress,0));
  background:linear-gradient(90deg,var(--cyan,#00e5cc),var(--gold,#ffc145));
  transition:transform .08s linear;
}

/* ---------- 6. SMOOTH SCROLL ---------- */
html.flow-smooth{scroll-behavior:auto}

/* Stop the page rubber-banding past the footer into empty background.
   This has to be on the ROOT element - setting it only on <body> leaves the
   document-level bounce in place, which is what "the page scrolls below the
   bottom" actually is. Not gated on .flow-smooth: it should hold even if
   Lenis never loads.
   Trade-off: this also disables pull-to-refresh on the site. */
html{overscroll-behavior-y:none}
html.flow-smooth body{overscroll-behavior:none}

/* ---------- 7. REDUCED MOTION ---------- */
@media (prefers-reduced-motion:reduce){
  .flow-ready [data-flow]{opacity:1!important;transform:none!important;filter:none!important;transition:none}
  .flow-line > span{transform:none!important;transition:none}
  [data-flow-scrub]{transform:none!important;opacity:1!important;letter-spacing:normal!important}
  .flow-mood,.flow-mood__orb,.flow-narrative__panel{transition:none}
  .flow-rail__fill{transition:none}
}
