/* ==========================================================================
   AVEN — flow.css
   A purely-additive cinematic scroll-FLOW layer. Pairs with flow.js.
   Vanilla CSS only — no libraries, no build, no CDN. Delete these two files
   and the site is byte-for-byte behaviourally unchanged.

   What it adds (none of it fights the existing reveal system):
     1. Section seams   soft gradient bleeds so band-deep ↔ band-panel melt
                        instead of hard-cutting. Pure CSS, always on.
     2. Parallax hook   depth drift on section media (flow.js writes the
                        `translate` property; see note below).
     3. Choreography    varied entrances — eyebrows slide, columns part
                        left/right, pull-quotes wipe, hero media scales — so
                        the eye never habituates to one identical reveal.
     4. Progress rail   a thin gold line that fills with scroll depth.
     5. Hero→Explore    a scrim + hero-media recede so the film hands off to
                        the room instead of cutting.

   ── The one trick that makes this SAFE ──────────────────────────────────
   The site already animates .reveal via the `transform` property (a slow
   ~1s transition on two separate observers). If we also wrote `transform`
   we'd clobber the reveal mid-flight. So every motion here is expressed with
   the INDIVIDUAL transform properties — `translate` and `scale` — plus
   `clip-path`. These compose with `transform` instead of replacing it, and
   they carry no inherited transition, so per-frame parallax stays crisp.
   `translate`/`scale` are unused anywhere else in this codebase (checked),
   so there is nothing to collide with. Where a browser lacks them, flow.js
   feature-detects and simply skips that effect — content is never hidden.

   Safe-degrade contract (mirrors motion.css):
     - Every entrance OFFSET is gated on <html class="flow-on">, which flow.js
       adds as its first act and REMOVES if setup throws. No JS ⇒ no flow-on
       ⇒ no offsets ⇒ nothing is displaced or hidden.
     - Entrance offsets are released by the SAME `.in` hook the site already
       toggles, and every offset target lives inside an opacity-gated .reveal
       whose own failsafes reveal it. flow.js adds a further `flow-fallback`
       backstop that neutralises all offsets after 3.2s no matter what.
     - Seams are NOT gated — they are static, harmless, and want to render
       even if flow.js never runs.
     - prefers-reduced-motion: reduce ⇒ zero transforms/animation. Seams and
       the (scroll-tied, not decorative) rail stay; everything else is flat.

   Palette literals match the site's :root exactly:
     ink #0b171e · ink2 #06121a · panel #102630 · panel2 #16323c
     gold #e7ab5c · gold-soft #f3c886 · bone #f3ecde · signal #d3f227
   ========================================================================== */

/* ---- Tunable tokens (specificity 0; override freely) -------------------- */
:root{
  --flow-ease:      cubic-bezier(.16, .84, .28, 1);  /* matches --mo-ease    */
  --flow-ease-soft: cubic-bezier(.22, .61, .36, 1);  /* gentler, longer tail */
  --flow-dur:       .85s;   /* eyebrow slide                                 */
  --flow-dur-slow:  1.15s;  /* columns / pull wipe / media scale            */
  --flow-seam-h:    clamp(3rem, 9vh, 8rem);   /* seam fade height — longer & */
                            /* softer, still always < a band's               */
                            /* clamp(5rem,12vh,9.5rem) padding, so the        */
                            /* overlay only ever covers empty padding         */
  --flow-eyb-x:     16px;   /* eyebrow horizontal travel                     */
  --flow-col-x:     34px;   /* split-column horizontal travel (≥820px only)  */
  --flow-rise-scale:1.045;  /* media scale-up entrance                       */
}

/* ==========================================================================
   1 · SECTION SEAMS  — fade each band's BOTTOM edge into the next band's
   top colour, so the deep↔panel hard cut becomes a cross-dissolve. Single-
   sided (upper ::after only) is enough: the fade ends exactly on the
   neighbour's colour, which the neighbour then continues. Pure CSS.

   The overlay sits inside the band's bottom PADDING (height always < padding)
   with pointer-events:none, so it never covers content or intercepts taps,
   and needs no stacking-context gymnastics.
   ========================================================================== */
.band::after,
.divider::after{
  content:"";
  position:absolute;
  left:0; right:0; bottom:0;
  height:var(--flow-seam-h);
  pointer-events:none;
  /* --seam defaults to transparent ⇒ if :has() is unsupported the overlay is
     simply invisible (graceful no-op). Neighbour rules below set the colour.
     An eased three-stop ramp (hold clear, then a mid-alpha of the neighbour,
     then full) reads as a soft cross-dissolve rather than a linear wipe — so
     consecutive bands melt instead of butting. color-mix is well within this
     build's baseline (the site already relies on :has()); if it were absent
     the whole declaration is simply dropped and the seam no-ops, never muddy. */
  background:linear-gradient(to bottom,
      transparent 0%,
      color-mix(in srgb, var(--seam, transparent) 40%, transparent) 60%,
      var(--seam, transparent) 100%);
}

/* Neighbour-aware seam colours (adjacent-sibling + :has, both already used by
   this site's own CSS, so support is a given on the target browser). */
.band:has(+ .band-panel)::after     { --seam:var(--panel); }   /* → #102630 */
.band:has(+ .band-deep)::after      { --seam:var(--ink);   }   /* → #0b171e (deep gradient TOP) */
.band-panel:has(+ footer)::after    { --seam:var(--ink2);  }   /* → #06121a (footer bg) */
.band-panel:has(+ .divider)::after  { --seam:#0a1a22;      }   /* who → divider (approx dark) */
.divider:has(+ .band-deep)::after   { --seam:var(--ink);   }   /* divider → search */

/* The divider carries its own layered art (.pbg/.veil z0, .dq z2); keep the
   seam above the art but below the quote so nothing is covered. */
.divider::after{ z-index:1; }

/* ==========================================================================
   2 + 3 · ENTRANCE CHOREOGRAPHY
   Gated on html.flow-on. Neutral (identity) is the BASE state + a transition;
   the pre-`.in` OFFSET is applied only while the governing .reveal has not yet
   entered (`.reveal:not(.in)`). When the site's observers add `.in`, the base
   neutral applies and the individual property transitions home.

   Selectors cover BOTH shapes seen on the page:
     · the tagged element IS the reveal            → `.reveal…​.flow-x`
     · the tagged element is INSIDE a reveal wrap   → `.reveal… .flow-x`
   ========================================================================== */

/* -- base neutral + transitions (harmless when no offset is ever applied) --
   Each element TYPE gets its own easing, duration and a small offset so a
   section's parts DON'T all snap home on the same curve at the same instant
   (the "staccato" the seams were fighting). Text leads; media and quotes
   trail a beat and settle on the softer, longer-tailed ease — the band reads
   as one slow dissolve rather than a burst of simultaneous pop-ins. */
html.flow-on .flow-eyb{
  translate:0 0;
  transition:translate var(--flow-dur) var(--flow-ease-soft) .04s;
}
html.flow-on .flow-col-l,
html.flow-on .flow-col-r{
  translate:0 0;
  transition:translate var(--flow-dur-slow) var(--flow-ease-soft);
  /* stay in step with motion.js's per-column stagger (it sets --stagger). */
  transition-delay:calc(var(--stagger, 0) * var(--mo-stagger, 70ms));
}
html.flow-on .flow-rise-scale{
  scale:1;
  transition:scale var(--flow-dur-slow) var(--flow-ease-soft) .06s;
}
html.flow-on .flow-wipe{
  clip-path:inset(0 0 0 0);
  transition:clip-path var(--flow-dur-slow) var(--flow-ease) .1s;
}

/* -- pre-`.in` offsets (only before the governing .reveal enters) ---------- */

/* Eyebrow labels slide in from the left — the little rule line draws out. */
html.flow-on .reveal:not(.in) .flow-eyb,
html.flow-on .reveal:not(.in).flow-eyb{
  translate:calc(var(--flow-eyb-x) * -1) 0;
}

/* Pull-quotes wipe open left→right (they live inside opacity-gated reveals,
   so this is a flourish on an already-guarded block, never a new hide path). */
html.flow-on .reveal:not(.in) .flow-wipe,
html.flow-on .reveal:not(.in).flow-wipe{
  clip-path:inset(0 100% 0 0);
}

/* Media settle with a subtle scale-up (distinct from the text's rise). */
html.flow-on .reveal:not(.in) .flow-rise-scale,
html.flow-on .reveal:not(.in).flow-rise-scale{
  scale:var(--flow-rise-scale);
}

/* Split columns part from opposite sides — only where there are two columns
   side-by-side (≥820px). Below that they stack, so horizontal travel is off
   and they simply use the base vertical reveal. */
@media (min-width:820px){
  html.flow-on .reveal:not(.in) .flow-col-l,
  html.flow-on .reveal:not(.in).flow-col-l{
    translate:calc(var(--flow-col-x) * -1) 0;
  }
  html.flow-on .reveal:not(.in) .flow-col-r,
  html.flow-on .reveal:not(.in).flow-col-r{
    translate:var(--flow-col-x) 0;
  }
}

/* ==========================================================================
   PARALLAX HOOK
   flow.js writes `translate` on these each frame (only while on-screen). No
   inherited transition, so the drift tracks scroll exactly. The class only
   carries a compositor hint; flow.js also toggles will-change per element.
   ========================================================================== */
html.flow-on .flow-parallax{ backface-visibility:hidden; }

/* ==========================================================================
   4 · SCROLL-PROGRESS RAIL — thin gold line, top edge, fills with depth.
   Fixed above the nav (z55) but below the mobile thumbbar (z60) and toast
   (z80). Honours the top safe-area inset. pointer-events:none — never blocks.
   ========================================================================== */
.flow-rail{
  position:fixed;
  top:env(safe-area-inset-top, 0px);
  left:0; right:0;
  height:3px;
  z-index:55;
  pointer-events:none;
  background:rgba(231,171,92,.10);         /* faint track                    */
}
.flow-rail-fill{
  height:100%;
  width:100%;
  transform:scaleX(0);                     /* flow.js drives scaleX(0..1)     */
  transform-origin:left center;
  background:linear-gradient(90deg, var(--gold, #e7ab5c), var(--gold-soft, #f3c886));
  box-shadow:0 0 10px -1px rgba(231,171,92,.7);
  transition:transform .1s linear;         /* micro-smoothing between frames  */
  will-change:transform;
}

/* ==========================================================================
   5 · HERO → EXPLORE HANDOFF
   A fixed, top-weighted ink scrim (flow.js ramps its opacity across the hero
   exit) plus a gentle recede on the hero media (flow.js writes scale/opacity/
   translate). The scrim sits above hero art (max z4) but below the nav (z50).
   ========================================================================== */
.flow-handoff{
  position:fixed;
  inset:0;
  z-index:6;
  pointer-events:none;
  opacity:0;                               /* flow.js ramps 0 → ~.42 → 0      */
  /* A warm gold bloom (echoing the hero-veil's own warm radial) rides on top
     of the ink dissolve, so the film doesn't cut to a flat dark band — it
     hands its last warm light down INTO the room. Top-weighted and clear
     through the lower third, so the hero's bottom CTAs are never in it (and
     at rest the whole scrim is opacity 0 anyway). */
  background:
     radial-gradient(120% 82% at 66% 20%, rgba(231,171,92,.17), transparent 60%),
     linear-gradient(180deg,
              var(--ink, #0b171e) 0%,
              rgba(11,23,30,.55) 26%,
              rgba(11,23,30,0)   62%);
  will-change:opacity;
}

/* ==========================================================================
   FAILSAFE — flow.js adds html.flow-fallback ~3.2s in. It forces every
   entrance offset back to neutral no matter what the reveal observers did.
   Parallax is deliberately excluded (its drift is tiny and never hides).
   ========================================================================== */
html.flow-fallback .flow-eyb,
html.flow-fallback .flow-col-l,
html.flow-fallback .flow-col-r,
html.flow-fallback .flow-rise-scale,
html.flow-fallback .flow-wipe{
  translate:0 0 !important;
  scale:1 !important;
  clip-path:none !important;
  transition:none !important;
}

/* ==========================================================================
   REDUCED MOTION — required path. Everything visible, zero transforms/anim.
   Seams stay (static). The rail stays (it tracks scroll like a scrollbar, not
   decorative motion) but loses its easing and glow.
   ========================================================================== */
@media (prefers-reduced-motion: reduce){
  html.flow-on .flow-eyb,
  html.flow-on .flow-col-l,
  html.flow-on .flow-col-r,
  html.flow-on .flow-rise-scale,
  html.flow-on .flow-wipe{
    translate:0 0 !important;
    scale:1 !important;
    clip-path:none !important;
    transition:none !important;
  }
  html.flow-on .flow-parallax{ translate:0 0 !important; }
  .flow-handoff{ display:none !important; }
  .flow-rail-fill{ transition:none !important; box-shadow:none !important; }
}

/* ==========================================================================
   6 · SEGMENT DISSOLVE — scroll-linked seam pass. Pairs with flow.js §6.
   flow.js writes ONE custom property (--dz, 0..1, smoothstepped) per active
   section per frame; this CSS maps it onto cheap named carriers. The film
   recedes, the next room receives — filter/opacity ONLY, never transform,
   never .reveal opacity, no transition on any scroll-linked property.

   FAILSAFE REASONING (why this can never hide content): the only channels
   used are blur, brightness and a floored opacity. No JS / setup throw ⇒
   flow-on absent or --dz absent ⇒ calc(var(--dz,0)*…) = 0 ⇒ blur(0)
   brightness(1) opacity(1) — pixel-identical to today. JS dies MID-seam ⇒
   the worst possible frozen state is blur ≤ var(--dz-blur-max), brightness
   ≥ .82, opacity ≥ .88 — softened, dimmed, but fully readable and fully
   present. There is no value of --dz at which content disappears.
   ========================================================================== */
:root{
  --dz-blur-max:2px;        /* budget ceiling 2.5px phones — this is the 80% take */
  --dz-dim:.18;             /* brightness floor 1 − .18 = 0.82                    */
  --dz-media-fade:.12;      /* opacity floor 0.88 — non-reveal media only         */
  --dz-bloom:.10;           /* gold rgba(231,171,92,α) hand-forward, ≥820px only  */
}
@media (min-width:820px){
  :root{ --dz-blur-max:3.2px; }   /* ceiling 4px wide — still the 80% take */
}

/* -- carriers ---------------------------------------------------------------
   Reveal-gated carriers match ONLY once `.in` (specificity 0-6-1 beats both
   index.html's inline .js .reveal rule and motion.css:49), so the
   pre-entrance blur/offset state is never pre-empted; entrance in flight =
   entrance wins (dz≈0 mid-viewport anyway). Non-reveal carriers match only
   while the section is seam-active. */
html.flow-on .band[data-dz-active] .dz:not(.reveal),
html.flow-on .band[data-dz-active] .reveal.in.dz{
  filter:blur(calc(var(--dz, 0) * var(--dz-blur-max)))
         brightness(calc(1 - var(--dz, 0) * var(--dz-dim)));
}

/* Reveal coexistence: the OPERATIVE entrance transition is motion.css:49-59
   (motion.css loads AFTER the inline sheet and out-cascades index.html's
   .js .reveal rule whenever motion.js runs — which is always). Re-declare
   it in LONGHANDS, preserving durations, easing and the --stagger cascade
   delay EXACTLY, with only the filter track → 0s — so the scroll-driven
   filter never smears through the entrance easing and row staggers are
   never reset. Applies only while [data-dz-active]; at rest motion.css's
   own rule returns untouched. */
html.flow-on .band[data-dz-active] .reveal.in.dz{
  transition-property:opacity,transform,filter;
  transition-duration:var(--mo-dur,.9s),var(--mo-dur,.9s),0s;
  transition-timing-function:var(--mo-ease,ease),var(--mo-ease,ease),ease;
  transition-delay:calc(var(--stagger,0)*var(--mo-stagger,70ms)),calc(var(--stagger,0)*var(--mo-stagger,70ms)),0s;
}

/* Non-reveal media carriers additionally fade — floor .88, never hidden.
   (.dz-media is never assigned to a .reveal: that opacity belongs to the
   reveal system, one writer per property, ever.) */
html.flow-on .band[data-dz-active] .dz-media{
  opacity:calc(1 - var(--dz, 0) * var(--dz-media-fade));
}

/* Video figures and the continuously-animating montage soft-focus on wide
   screens only — blurring a playing/animating full-bleed raster is flow.js's
   one documented fps hazard (flow.js:48-53). The transition longhands ride
   inside the same gate: a sub-820 .dz-wide has no dz filter, so it must
   also keep its stock entrance filter easing. */
@media (min-width:820px){
  html.flow-on .band[data-dz-active] .dz-wide:not(.reveal),
  html.flow-on .band[data-dz-active] .reveal.in.dz-wide{
    filter:blur(calc(var(--dz, 0) * var(--dz-blur-max)))
           brightness(calc(1 - var(--dz, 0) * var(--dz-dim)));
  }
  html.flow-on .band[data-dz-active] .reveal.in.dz-wide{
    transition-property:opacity,transform,filter;
    transition-duration:var(--mo-dur,.9s),var(--mo-dur,.9s),0s;
    transition-timing-function:var(--mo-ease,ease),var(--mo-ease,ease),ease;
    transition-delay:calc(var(--stagger,0)*var(--mo-stagger,70ms)),calc(var(--stagger,0)*var(--mo-stagger,70ms)),0s;
  }
}
/* Their captions dissolve on phones instead (cheap text), then hand the job
   to the parent's blur on wide — never both, never double-blur. */
@media (max-width:819.98px){
  html.flow-on .band[data-dz-active] .dz-narrow:not(.reveal){
    filter:blur(calc(var(--dz, 0) * var(--dz-blur-max)))
           brightness(calc(1 - var(--dz, 0) * var(--dz-dim)));
  }
}

/* -- gold hand-forward ------------------------------------------------------
   Seams pass the light (#e7ab5c) over ink — warmth-preserving, never gray.
   Clone of roomfp.css's --fp-enter bloom idiom: top-anchored, height 34%,
   opacity:var(--dz), pointer-events:none. Painted at z1 it sits above the
   band background and WASHES OVER in-flow .wrap content at alpha ≤ .10 —
   a tint, never a cover (this wash IS the hand-forward); all fixed chrome
   (nav/thumbbar/toast — body-level) stays above and no filter ever sits on
   an ancestor of it. The pseudo is GENERATED only while [data-dz-active],
   so its will-change is intrinsically on/off gated. ≥820px only. */
@media (min-width:820px){
  html.flow-on .band[data-dz-active]::before{
    content:"";
    position:absolute; left:0; right:0; top:0; height:34%;
    z-index:1;
    pointer-events:none;
    opacity:var(--dz, 0);
    background:radial-gradient(120% 100% at 50% 0%,
        rgba(231,171,92,var(--dz-bloom)), transparent 70%);
    will-change:opacity;
  }
}

/* -- flow-fallback neutralizer ---------------------------------------------
   flow.js adds .flow-fallback unconditionally at 3.2s on EVERY load — it is
   the entrance-offset backstop, not a death signal. This rule parks --dz at
   rest from CSS for the case where setup tagged carriers but the loop never
   wrote: a LIVE loop's inline setProperty('--dz', …) out-ranks it (inline
   beats author non-important), so a healthy dissolve is untouched; a dead
   one settles sharp. Frozen-mid-value is covered by the floors above. */
html.flow-fallback .band{ --dz:0; }

/* -- reduced motion — required path: zero, flat, everything visible --------
   Belt-and-braces: flow.js never registers the dissolve under reduce, so
   [data-dz-active] should never exist there at all. */
@media (prefers-reduced-motion: reduce){
  html.flow-on .band[data-dz-active] .dz,
  html.flow-on .band[data-dz-active] .dz-wide,
  html.flow-on .band[data-dz-active] .dz-narrow{ filter:none !important; }
  html.flow-on .band[data-dz-active] .dz-media{ opacity:1 !important; }
  html.flow-on .band[data-dz-active]::before{ content:none !important; }
  html.flow-on .band[data-dz-active] .reveal.in.dz,
  html.flow-on .band[data-dz-active] .reveal.in.dz-wide{ transition:none !important; }
}
