/* styles2.css — mobile + responsive @media rules, split out of styles.css to stay
   under Instagram in-app-browser ~50KB/file CSS parse cap. Load AFTER styles.css. */
@media(max-width:680px){
  :root{--rail:0px;}
  /* scroll the ROOT (native momentum/inertia); body must NOT be a scroll container */
  html{overflow-x:hidden;}
  body.hx{overflow:visible;height:auto;min-height:100vh;}
  .htrack{display:block;height:auto;min-height:0;overflow:visible;scroll-snap-type:none;will-change:auto;}
  /* kill scroll-jank: the fixed grain overlay (mix-blend) repaints the whole viewport every frame */
  body::after{display:none;}
  /* .bgfx (desktop "helix of light" pattern) is now enabled on mobile too — shows through the translucent panels below */
  .hcue,.swipehint{display:none!important;}

  /* sections: full width, editorial spacing (tightened: was clamp(56,9vh,80) = 152px combined gaps) */
  .htrack > section,.htrack > footer,
  .feature,.hero--bold,.merge,.bio,.whofor,.alt,.cta{
    position:relative;display:block;width:100%;min-width:0;max-width:100%;
    height:auto;min-height:auto;overflow:visible;scroll-snap-align:none;
    scroll-margin-top:64px;padding:clamp(40px,5.5vh,52px) 24px;}
  .htrack > section.merge{padding:clamp(40px,5.5vh,52px) 24px;}
  .htrack > section.cta{min-height:auto;}

  /* inner wrappers full-width, allow shrink */
  .frame,.hero__col1,.hero__col2,.hero__more,.feature__body,
  .merge__left,.merge__right,.merge__head,.whofor__text,.how__text,
  .cta__inner,.cta__intro,.cta__form,.bio__text{width:100%;max-width:100%;min-width:0;}
  /* multi-col grids/areas -> simple block stacking (kills desktop grid-area collisions) */
  .feature__in,.feature__body,.merge__grid,.merge__left,.merge__right,
  .whofor__in,.how__in,.cta__grid,.cta__fields,.cta__inner,.vs,.feature__copy{
    display:block;width:100%;max-width:100%;min-width:0;}
  .hero__heads{display:flex;flex-direction:column;gap:16px;width:100%;max-width:100%;min-width:0;}  /* single rhythm source (was 40px inherited gap stacking with element margins) */
  .hero__col1,.hero__col2{display:contents;}
  .htrack p,.htrack h1,.htrack h2,.htrack h3,.htrack li{overflow-wrap:break-word;}

  /* all NON-hero content visible (hero is driven by the intro below; scroll sections by .m-reveal) */
  /* NOTE: the gap (.feature--gap) AND merge (.merge) are excluded here — each runs its own pinned beat sequence (see below) */
  .whofor__text,.whofor__pq,
  .cta__intro,.cta__form{opacity:1!important;transform:none!important;max-height:none!important;}
  [data-split] .w{opacity:1!important;transform:none!important;filter:none!important;}
  .cta__form{pointer-events:auto!important;}
  .vs__col--b{animation:none;}

  /* ===== editorial type system ===== */
  .eyebrow,.hero__above{font-family:var(--sans);font-size:.78rem;font-weight:700;letter-spacing:.16em;
    text-transform:uppercase;color:var(--accent);margin:0 0 16px;line-height:1.4;}
  .hero__h2,.feature__kicker,.merge__headline,.whofor h2,.how__text h2,.cta h2{
    font-family:var(--serif);font-weight:700;font-size:clamp(1.95rem,7.6vw,2.45rem);
    line-height:1.08;letter-spacing:-0.02em;color:var(--ink);max-width:100%;margin:0;}
  .feature__headline{font-family:var(--serif);font-weight:700;
    font-size:clamp(1.3rem,4.6vw,1.55rem);line-height:1.2;color:var(--accent-deep);max-width:100%;margin:0;}
  .merge__sub{font-family:var(--serif);font-weight:500;
    font-size:clamp(1.3rem,4.6vw,1.55rem);line-height:1.22;color:var(--ink-2);max-width:100%;margin:0;}
  .lead,.prose p,.feature__copy p,.merge__prose p,.whofor .prose p,.how__text .prose p,
  .bio__text .prose p,.cta .lead{font-family:var(--sans);font-size:1.05rem;line-height:1.62;color:var(--ink-2);max-width:100%;}
  .prose .em,.merge__prose .em{color:var(--ink);font-weight:600;}
  .pq,.feature__pq,.whofor__pq{font-family:var(--serif);font-weight:700;
    font-size:clamp(1.45rem,5.6vw,1.8rem);line-height:1.22;letter-spacing:-0.015em;color:var(--ink);max-width:100%;}
  .pq .it,.feature__pq .it,.whofor__pq .it{font-style:italic;color:var(--accent);}
  /* hero subcopy: force the client-requested 3-line grouping (mobile only, words unchanged;
     desktop keeps its natural wrap - see index.html's .lead__ln spans) */
  .hero__more .lead .lead__ln{display:block;}

  /* ===== top bar + hamburger menu ===== */
  .railnav{opacity:1!important;height:auto;min-height:60px;flex-direction:row;flex-wrap:wrap;align-items:center;
    align-content:flex-start;left:0;right:0;top:0;bottom:auto;width:auto;padding:0 18px;gap:0;
    border-right:0;border-bottom:1px solid var(--hairline);background:var(--paper);}  /* solid, no blur (blur janks scroll) */
  .railnav__brand{order:1;flex:1 1 auto;min-width:0;max-width:none;height:60px;display:flex;align-items:center;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:1.08rem;}  /* max-width:none overrides desktop 8ch cap: full wordmark + grows to push toggle right */
  .navtoggle{display:inline-flex;order:2;flex:0 0 auto;align-items:center;justify-content:center;height:60px;width:44px;margin-right:-8px;}
  /* the top bar's bottom divider IS the scroll-progress bar (fills left -> right toward the page bottom) */
  .railnav__progress{top:58px;bottom:auto;left:0;right:auto;width:100%;height:2.5px;
    transform:scaleX(var(--np,0));transform-origin:left center;}
  .railnav__links{order:3;display:none;flex-basis:100%;width:100%;}
  .railnav__foot{order:4;display:none;flex-basis:100%;width:100%;}
  .railnav.nav-open{background:var(--paper);border-bottom:1px solid var(--hairline);
    padding-bottom:20px;box-shadow:0 18px 34px rgba(23,19,16,.10);max-height:100vh;overflow-y:auto;}
  .railnav.nav-open .railnav__links{display:flex;flex-direction:column;gap:2px;width:100%;padding-top:8px;margin:0;border-top:1px solid var(--hairline);}
  .railnav.nav-open .railnav__foot{display:flex;width:100%;margin-top:16px;}
  .railnav__links a:not(.btn){font-family:var(--serif);font-size:1.3rem;font-weight:500;padding:11px 0;min-height:44px;display:flex;align-items:center;}
  .railnav .nav__has-sub{flex-direction:column;align-items:flex-start;width:100%;}
  .railnav .nav__sub{position:static;opacity:1!important;visibility:visible!important;transform:none!important;
    box-shadow:none;border:0;background:transparent;margin:0;padding:0 0 6px 16px;min-width:0;}
  .railnav .nav__sub a{padding:9px 0;min-height:44px;display:flex;align-items:center;font-family:var(--sans);font-size:.95rem;color:var(--ink-2);}  /* 44px touch target (was 40px) */
  .railnav .nav__has-sub::after{display:none;}
  .railnav .btn{display:inline-flex;align-items:center;justify-content:center;min-height:46px;padding:0 22px;width:100%;border-radius:999px;}
  .btn,a{-webkit-tap-highlight-color:transparent;}

  /* ===== hero — MOBILE POSTER: giant name BEHIND Fil's head (mirrors desktop), photo large + centred,
         copy spaced cleanly below. Was a cramped name -> eyebrow -> statement -> lead stack. ===== */
  /* min-height + tail padding trimmed (was 100svh + the base 40-52px pad): the poster hero was
     locking a full screen even when its content sat well short of it, leaving a large dead gap
     before the scroll cue and into the gap section below (client: "reduce all that white space"). */
  .htrack > section.hero--bold{padding-top:60px;padding-bottom:clamp(24px,3.4vh,34px);min-height:92svh;display:flex;flex-direction:column;justify-content:flex-start;position:relative;overflow:hidden;}
  .hero--bold > .frame{display:flex;flex-direction:column;}
  .hero__aura{inset:0;}  /* desktop inset:-12% bleeds past viewport on mobile -> 48px horizontal scroll; clamp to hero box */
  .hero__heads{gap:14px;}
  /* the poster stack: [name absolute BEHIND] portrait -> eyebrow -> copy frame */
  .hero--bold > .hero__portrait{order:1;}
  .hero--bold > .hero__above{order:2;}
  .hero--bold > .frame{order:3;}

  /* PORTRAIT: centred + large, sits OVER the name. Restored to its original min(118vw,500px)
     (a prior pass shrank this to min(100%,460px) misreading a complaint that was actually
     about the NAME text below clipping at the edges, not the portrait). */
  .hero__portrait{align-self:center;width:min(118vw,500px);margin:clamp(2px,0.6vh,10px) 0 0;z-index:2!important;}

  /* NAME behind the head: absolute + centred, big enough that FILIPPOU frames the head both sides,
     stacked FILIMON / FILIPPOU like desktop. z-index 1 keeps it under the portrait (z-index 2).
     Font-size reduced from min(20.5vw,108px): at that size FILIPPOU (the longer word) was wider
     than the viewport and bled off both edges. 17.3vw keeps ~16-24px clear on each side at
     375-430px (measured), still framing the head, no cap hit in that range (92px cap only
     engages near the 680px upper edge of this media query). */
  .hero--bold > .hero__name{position:absolute!important;left:50%;transform:translateX(-50%);
    top:clamp(74px,11.5vh,138px);z-index:1;pointer-events:none;white-space:nowrap;
    display:flex;flex-direction:column;align-items:center;
    font-family:var(--serif);font-weight:900;text-transform:uppercase;color:var(--ink);
    font-size:min(17.3vw,92px);line-height:.82;letter-spacing:-0.02em;margin:0;}
  .hero__name span{display:block;}

  /* COPY below the poster: eyebrow -> statement -> lead, cleanly spaced, clearing the scroll cue */
  .hero__above{order:1;margin:clamp(2px,0.6vh,8px) 0 0;max-width:none;font-size:.7rem;letter-spacing:.14em;color:var(--accent);}
  .hero__h2{order:2;font-family:var(--serif);font-weight:800;text-transform:none;
    font-size:clamp(1.6rem,6.6vw,2.15rem);line-height:1.1;letter-spacing:-0.01em;color:var(--ink);margin:clamp(12px,2vh,18px) 0 0;}
  .hero__more{order:3;margin-top:clamp(12px,2vh,18px);}
  .hero__more .lead{margin:0;font-size:clamp(.98rem,4vw,1.08rem);line-height:1.5;color:var(--ink-2);}
  .hero__more .hero__cta{display:none;}  /* specificity must match desktop `.hero__more .hero__cta`; CTA button replaced by the scroll cue on mobile */
  /* photo reveal faster on mobile (client: speed up the silhouette -> photo handover):
     fade the photo in AT the pre-reveal handoff (as the line dissolves) instead of waiting
     for dismiss — on mobile the hero FLIP is skipped, so nothing else reveals it early. */
  .hero__portrait{transition:opacity .45s ease 0s;}
  html.pre-reveal .hero__portrait{opacity:1;}
  /* scroll-down cue — pinned to the hero's bottom-RIGHT so it clears the left-aligned lead */
  .hero__scroll{display:inline-flex;flex-direction:column;align-items:center;gap:6px;
    position:absolute!important;z-index:3;right:24px;left:auto;bottom:calc(clamp(14px,2.6vh,26px) + env(safe-area-inset-bottom,0px));margin:0;
    background:none;border:0;padding:6px 10px 6px 0;cursor:pointer;-webkit-tap-highlight-color:transparent;  /* padding -> ~44px tap target; safe-area keeps it off the home indicator */
    font-family:var(--sans);font-size:12px;font-weight:600;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-2);}  /* ink-2 not ink-3: AA contrast on the light hero */
  .hero__scroll-arrow{width:13px;height:13px;border-right:2px solid var(--accent);border-bottom:2px solid var(--accent);
    transform:rotate(45deg);animation:scrollNudge 1.7s ease-in-out infinite;}
  @keyframes scrollNudge{0%,100%{transform:rotate(45deg) translate(0,0);opacity:.55;}50%{transform:rotate(45deg) translate(3px,3px);opacity:1;}}

  /* ----- INTRO: name (behind head) fades up first, then eyebrow -> statement -> lead -> scroll stagger in.
         The name is absolute + centred, so its keyframe MUST keep translateX(-50%) or it jumps off-centre. ----- */
  html.js .hero--bold > .hero__name{opacity:0;animation:heroPosterName .9s cubic-bezier(.16,1,.3,1) .15s both;}
  html.js .hero__above{opacity:0;animation:heroRiseIn .7s cubic-bezier(.16,1,.3,1) .7s both;}
  html.js .hero__h2{opacity:0;animation:heroRiseIn .7s cubic-bezier(.16,1,.3,1) .9s both;}
  html.js .hero__more{opacity:0;animation:heroRiseIn .7s cubic-bezier(.16,1,.3,1) 1.1s both;}
  html.js .hero__scroll{opacity:0;animation:heroRiseIn .7s cubic-bezier(.16,1,.3,1) 1.4s both;}
  @keyframes heroPosterName{from{opacity:0;transform:translate(-50%,20px);}to{opacity:1;transform:translate(-50%,0);}}
  @keyframes heroNameIn{from{opacity:0;transform:translateY(22px) scale(.985);}to{opacity:1;transform:none;}}
  @keyframes heroRiseIn{from{opacity:0;transform:translateY(16px);}to{opacity:1;transform:none;}}

  /* ===== gap (feature) ===== */
  /* reduced-motion/no-JS fallback section padding trimmed to match the hero's tightened rhythm
     (client: "reduce all that white space" from hero into the gap section) */
  .htrack > section.feature{padding-top:clamp(28px,4vh,36px);padding-bottom:clamp(24px,3.4vh,34px);}
  .feature__kicker{font-size:clamp(1.7rem,6.6vw,2.15rem);line-height:1.2;}  /* the beat statement — a touch larger since it stands alone, centred */
  .feature__body{margin-top:clamp(16px,2.4vh,22px);}
  .feature__headline{color:var(--accent-deep);margin:0 0 18px;font-size:clamp(1.5rem,6vw,2rem);}
  .feature__points{list-style:none;padding:0;margin:0;perspective:none;}
  .feature__points .fold{display:flex;align-items:baseline;gap:.5em;font-family:var(--serif);font-weight:600;
    font-size:1.5rem;line-height:1.3;color:var(--ink);margin:0 0 8px;}  /* larger key points (was 1.2rem) */
  .feature__points .fold:last-child{margin-bottom:0;}
  .feature__points .fold::before{content:"";flex:none;width:.32em;height:.32em;border-radius:50%;
    background:var(--accent);transform:translateY(-.18em);}
  .feature__copy{display:grid;gap:16px;margin:0;}
  .feature__copy p{margin:0;}
  .feature__pq{margin:0;}

  /* ---- gap: PINNED SEQUENTIAL REVEAL (mobile) ----
     .gap-seq is added by main.js (mobile, motion-OK). Scroll pins the panel and
     steps through 3 beats one at a time, each centred: statement -> subhead+points
     -> copy+closing line (merged 2026-07-27, see index.html/main.js). Without .gap-seq
     (reduced-motion / no-JS) the section falls back to normal stacked flow, everything visible. */
  /* overflow MUST stay visible (beats `.htrack > section.feature{overflow:hidden}` line ~301):
     an overflow:hidden section becomes a scroll container and the sticky child pins to the
     section top (scrolls away) instead of the viewport. */
  /* height must track the beat count passed to pinSeq() in main.js (3, not 4) - a stale
     multiplier here pins the panel for a whole extra screen of empty scroll after the last beat. */
  .htrack > section.feature--gap.gap-seq{padding:0;min-height:0;height:calc(3 * 100svh);overflow:visible;position:relative;}
  /* specificity must beat `.htrack > section.feature > *{position:relative}` (line ~305) */
  .htrack > section.feature--gap.gap-seq > .feature__in{position:sticky;top:0;height:100svh;min-height:100svh;
    display:block;overflow:hidden;padding:0;}
  .feature--gap.gap-seq .feature__body{margin:0;}
  /* free the collapsed desktop heights on mobile in BOTH modes (opacity handled per-mode below) */
  .feature--gap .feature__copy,
  .feature--gap .feature__pq,
  .feature--gap .feature__points{max-height:none;overflow:visible;}
  .feature--gap .feature__points .fold{transform:none;opacity:1;}
  .feature--gap .feature__headline .w{opacity:1;transform:none;filter:none;}
  /* gap-seq mode: .feature__copy/.feature__pq no longer carry their own gapbeat class (they're
     now children of the wrapper .gapbeat--c, merged 2026-07-27) so their desktop base rule
     (opacity:0, collapsed) would otherwise still win - the wrapper's own opacity/transform is
     what actually drives the beat's fade now, so unconditionally clear the children's opacity here. */
  .feature--gap.gap-seq .feature__copy,
  .feature--gap.gap-seq .feature__pq{opacity:1;transform:none;margin-top:0;}
  /* reduced-motion / no-JS fallback: no pinning — stack everything, fully visible */
  .feature--gap:not(.gap-seq) .feature__kicker,
  .feature--gap:not(.gap-seq) .feature__copy,
  .feature--gap:not(.gap-seq) .feature__pq{opacity:1;transform:none;}
  .feature--gap:not(.gap-seq) .feature__body{margin-top:clamp(22px,3.2vh,30px);}
  .feature--gap:not(.gap-seq) .gapbeat--b{margin-bottom:clamp(18px,2.6vh,26px);}
  .feature--gap:not(.gap-seq) .feature__copy{margin-bottom:clamp(18px,2.6vh,26px);}
  /* each beat: absolutely centred in the sticky stage, faded/moved by data-beat */
  .feature--gap.gap-seq .gapbeat{position:absolute;left:0;right:0;top:50%;
    padding:0 24px;margin:0;max-width:none;
    transform:translateY(-44%);opacity:0;pointer-events:none;
    transition:opacity .55s ease,transform .75s cubic-bezier(.16,1,.3,1);}
  /* beat 3 (gapbeat--c) now carries the copy AND the closing pull-quote stacked together
     (merged 2026-07-27 - see index.html), so it needs its own internal rhythm instead of
     each child centring itself independently. */
  .feature--gap.gap-seq .gapbeat--c{display:flex;flex-direction:column;gap:clamp(20px,3.4vh,32px);}
  /* the active beat sits dead-centre, fully lit */
  .feature--gap.gap-seq[data-beat="0"] .gapbeat--a,
  .feature--gap.gap-seq[data-beat="1"] .gapbeat--b,
  .feature--gap.gap-seq[data-beat="2"] .gapbeat--c{opacity:1;transform:translateY(-50%);pointer-events:auto;}
  /* beats already passed lift up and out (upcoming ones wait just below at -44%) */
  .feature--gap.gap-seq[data-beat="1"] .gapbeat--a,
  .feature--gap.gap-seq[data-beat="2"] .gapbeat--a,
  .feature--gap.gap-seq[data-beat="2"] .gapbeat--b{opacity:0;transform:translateY(-60%);}
  /* progress dots (injected by main.js) — quiet signal that a pinned panel is stepping.
     Shared by both pinned sequences (gap + merge); positioned inside each sticky stage. */
  .seqdots{position:absolute;left:50%;transform:translateX(-50%);
    bottom:calc(clamp(22px,4.4vh,44px) + env(safe-area-inset-bottom,0px));
    display:flex;gap:9px;z-index:4;pointer-events:none;}
  .seqdots span{width:7px;height:7px;border-radius:50%;background:var(--hairline);
    transition:background .4s ease,transform .4s ease;}
  .seqdots span.done{background:var(--ink-3);}
  .seqdots span.on{background:var(--accent);transform:scale(1.35);}
  /* scroll cue (injected by main.js) — the same nudging chevron as the hero, telling people the
     pinned panel keeps going. Sits just above the dots; retires on the last beat (.seq-end). */
  .seqcue{position:absolute;left:50%;transform:translateX(-50%);
    bottom:calc(clamp(52px,9vh,88px) + env(safe-area-inset-bottom,0px));
    z-index:4;pointer-events:none;opacity:.9;transition:opacity .45s ease;
    display:flex;flex-direction:column;align-items:center;gap:8px;}
  .seqcue__label{font-family:var(--sans);font-size:12px;font-weight:600;letter-spacing:.2em;text-transform:uppercase;color:var(--ink-2);}
  .seqcue i{display:block;width:13px;height:13px;border-right:2px solid var(--accent);border-bottom:2px solid var(--accent);
    transform:rotate(45deg);animation:scrollNudge 1.7s ease-in-out infinite;}
  .seq-end .seqcue{opacity:0;}

  /* ---- merge: PINNED SEQUENTIAL REVEAL (mobile) ----
     Same engine as the gap. 4 beats: frame (headline + sub) -> explanation ->
     the pivot question -> the versus comparison (both cards + the resolution line
     at the bottom of the boxes). .merge-seq is added by main.js (mobile, motion-OK). */
  .htrack > section.merge.merge-seq{padding:0;min-height:0;height:calc(4 * 100svh);overflow:visible;position:relative;}
  .htrack > section.merge.merge-seq > .merge__grid{position:sticky;top:0;height:100svh;min-height:100svh;
    display:block;overflow:hidden;padding:0;}
  .merge.merge-seq .merge__left,.merge.merge-seq .merge__right,
  .merge.merge-seq .merge__prose{position:static;margin:0;max-width:none;}
  /* free the desktop-collapsed states on mobile; opacity governed by the mbeat wrappers */
  .merge.merge-seq .mbeat--2 p{opacity:1;transform:none;}
  .merge.merge-seq .vs{opacity:1;transform:none;}
  /* the two comparison cards slide up in turn when their beat lands, then the line fades in beneath */
  .merge.merge-seq .vs__col{opacity:1;transform:translateY(16px);transition:transform .65s cubic-bezier(.16,1,.3,1);}
  .merge.merge-seq[data-beat="3"] .vs__col--a{transform:none;transition-delay:.05s;}
  .merge.merge-seq[data-beat="3"] .vs__col--b{transform:none;transition-delay:.20s;}
  .merge.merge-seq .merge__close{opacity:0;transform:none;transition:opacity .6s ease;}
  .merge.merge-seq[data-beat="3"] .merge__close{opacity:1;transition-delay:.42s;}
  /* the versus beat expands to showcase the two cards distinctly, resolution line beneath */
  .merge.merge-seq .mbeat--4 .vs{display:flex;flex-direction:column;gap:clamp(22px,4.2vh,38px);margin:0 0 clamp(18px,3vh,28px);}
  .merge.merge-seq .mbeat--4 .vs__col{padding:clamp(20px,3vh,30px) clamp(20px,5.4vw,26px);border-radius:12px;}
  .merge.merge-seq .mbeat--4 .vs__label{margin-bottom:12px;}
  .merge.merge-seq .mbeat--4 .vs__statement{font-size:clamp(1.18rem,5vw,1.42rem);line-height:1.36;}
  .merge.merge-seq .mbeat--4 .merge__close{margin:0;text-align:center;font-size:clamp(1rem,4.2vw,1.12rem);line-height:1.5;color:var(--ink-2);}
  /* each beat: absolutely centred in the sticky stage, faded/moved by data-beat */
  .merge.merge-seq .mbeat{position:absolute;left:0;right:0;top:50%;
    padding:0 24px;margin:0;max-width:none;
    transform:translateY(-44%);opacity:0;pointer-events:none;
    transition:opacity .55s ease,transform .75s cubic-bezier(.16,1,.3,1);}
  .merge.merge-seq[data-beat="0"] .mbeat--1,
  .merge.merge-seq[data-beat="1"] .mbeat--2,
  .merge.merge-seq[data-beat="2"] .mbeat--3,
  .merge.merge-seq[data-beat="3"] .mbeat--4{opacity:1;transform:translateY(-50%);pointer-events:auto;}
  /* beats already passed lift up and out */
  .merge.merge-seq[data-beat="1"] .mbeat--1,
  .merge.merge-seq[data-beat="2"] .mbeat--1,.merge.merge-seq[data-beat="2"] .mbeat--2,
  .merge.merge-seq[data-beat="3"] .mbeat--1,.merge.merge-seq[data-beat="3"] .mbeat--2,.merge.merge-seq[data-beat="3"] .mbeat--3{opacity:0;transform:translateY(-60%);}
  /* reduced-motion / no-JS fallback: no pinning — stack everything, fully visible */
  .merge:not(.merge-seq) .merge__prose p,
  .merge:not(.merge-seq) .vs__col,
  .merge:not(.merge-seq) .merge__table,
  .merge:not(.merge-seq) .merge__close{opacity:1;transform:none;}
  .merge:not(.merge-seq) .vs__col{transition:none;}

  /* ===== merge ===== */
  .merge__head{margin:0 0 clamp(18px,2.6vh,26px);}
  .merge__headline{margin:0 0 12px;}
  .merge__prose{margin:0 0 clamp(24px,3.6vh,34px);}
  .merge__prose p{margin:0 0 14px;}
  .vs{gap:var(--s3);margin:0 0 var(--s3);}
  .vs__col{min-width:0;padding:var(--s3) var(--s3) var(--s4);}
  .vs__statement{font-size:1.1rem;}
  .merge__close{margin:0;}

  /* ===== bio — full-screen photo statement -> shrinks into place -> copy reveals (FLIP driven by main.js) ===== */
  .htrack > section.bio{display:flex;flex-direction:column;position:relative;}  /* specificity must beat `.htrack > section{display:block}` so order: works */
  /* Filimon cutout (commanding arms-crossed pose, background removed) — bigger, head near top, fades into cream */
  .bio__img{order:1;position:relative;right:auto;top:auto;bottom:auto;left:auto;transform:scale(1.15);transform-origin:center top;width:100%;
    aspect-ratio:3/4;height:auto;min-height:340px;max-height:82vh;
    /* the mask below fades the figure to fully transparent by 72% of this box's own height,
       so the remaining 72%-100% is dead, invisible space that still consumes flex layout
       height. Pull it back with a negative margin-bottom so .bio__text sits closer to where
       the figure actually finishes fading, instead of after that empty tail too (client
       request: too much void between the portrait and the eyebrow, 2026-07-30). Was -108px,
       tuned by eye at 390px only: measured against real rendered pixels (not the idealised
       72% mask math, which undercounts how far the fade tail actually reads as "visible"),
       -108px left under 8px of clearance at 390px width and OVERLAPPED the still-visible
       figure at narrower widths (360px measured ~-20px, i.e. the eyebrow sat on top of the
       still-solid torso). -76px keeps a deliberate ~23px clearance at 390px (still tight,
       matching the original client request) and clears ~12px at the narrowest tested width
       (360px), measured across 360x640/390x844/414x896/390x932, 2026-07-30. */
    margin-top:0;margin-bottom:-76px;backface-visibility:hidden;
    /* defensive decode-failure backdrop, matched to THIS panel's own fill: on mobile
       (<=680px) section.bio is painted var(--paper-3) by the SECTION CONTRAST block
       below (not var(--paper) — that's the hero/merge/whofor tone). Must track that
       fill exactly or a lighter plate appears behind the cutout (QA regression,
       2026-07-22). Real-alpha PNG fallback via image-set() — see the long comment on
       the desktop .bio__img rule in styles.css for why. */
    background-image:url("fil-bio-m.png?v=1");
    background-image:image-set(url("fil-bio-m.webp?v=4") type("image/webp"), url("fil-bio-m.png?v=1") type("image/png"));
    background-position:center top;background-size:contain;background-repeat:no-repeat;
    /* fade raised from 84% so the hands and the viewer-left waist bulge are fully melted, not just softened */
    -webkit-mask-image:linear-gradient(to bottom,#000 56%,rgba(0,0,0,0) 72%);
    mask-image:linear-gradient(to bottom,#000 56%,rgba(0,0,0,0) 72%);}
  .bio.in .bio__img{transform:scale(1.15);}   /* keep the zoom (was transform:none, neutralising a desktop centring transform that no longer exists) */
  /* main.js's mobile FLIP intro (statement -> shrink to placed spot) sets an INLINE transform
     on .bio__img directly, ending on img.style.transform='none' once settled (see the
     "Mobile BIO intro" block in main.js). Inline styles beat any normal-weight CSS rule
     regardless of specificity, so the two rules above cannot win once JS has run — only an
     !important declaration can, and only once it's scoped to fire AFTER the full-screen
     statement/shrink has been given its class hooks (bio-shown), so it never fights the
     entrance zoom itself. Reduced-motion visitors never run the FLIP at all (main.js bails
     out before touching .bio__img's inline style), so for them the base rule above already wins. */
  .bio-revealed .bio__img{transform:scale(1.15)!important;}
  /* the 1.15 scale grows .bio__img slightly wider than its own placed footprint (which exactly
     filled the section's padded width), bleeding a few px past the viewport edge. .htrack
     section.bio otherwise keeps overflow:visible (needed for the FLIP intro, which briefly
     grows .bio__img to a near-full-viewport statement, position:relative — clipping .bio while
     THAT plays would cut the statement off). Gate the clip to bio-revealed only, i.e. after the
     statement has already shrunk back to its placed spot, so it only ever contains the resting
     zoom, never the intro. Reduced-motion visitors never get bio-revealed (the FLIP never runs,
     so .bio__img is never anything but "placed"), hence the plain :not() fallback below. */
  .bio.bio-revealed{overflow-x:hidden;}
  .bio:not(.bio-armed){overflow-x:hidden;}   /* JS-disabled / no-FLIP fallback: always placed, safe to clip from the start */
  .bio__text{order:2;position:static;padding-top:0;margin-top:clamp(6px,1.5vh,16px);}
  /* mobile: stack the stats, label beside each big number (3-across cramps the labels to 5 lines at 390px) */
  .bio__stats{order:3;position:static;width:100%;display:grid;grid-template-columns:1fr;gap:clamp(16px,2.6vh,22px);
    margin-top:clamp(28px,4vh,40px);border-top:1px solid var(--hairline);padding-top:var(--s3);}
  .bio .stat{display:flex;align-items:baseline;gap:16px;}
  .bio .stat .n{flex:none;}
  /* full-screen paper backdrop behind the photo during the statement (element created by JS) */
  .bio__veil{position:fixed;inset:0;background:var(--paper-3);opacity:0;pointer-events:none;z-index:29;}
  /* armed: hide photo + copy until the intro plays (!important beats the desktop .bio.in reveal rules that also run on mobile) */
  .bio-armed .bio__img{opacity:0!important;}
  .bio-armed.bio-shown .bio__img{opacity:1!important;}
  .bio-armed .bio__text,.bio-armed .bio__stats{opacity:0!important;transform:translateY(18px);}
  .bio-armed.bio-revealed .bio__text{opacity:1!important;transform:none;transition:opacity .65s cubic-bezier(.16,1,.3,1),transform .65s cubic-bezier(.16,1,.3,1);}
  .bio-armed.bio-revealed .bio__stats{opacity:1!important;transform:none;transition:opacity .65s cubic-bezier(.16,1,.3,1),transform .65s cubic-bezier(.16,1,.3,1);transition-delay:.18s;}
  .bio .stat .n{font-family:var(--serif);font-weight:900;font-size:clamp(2.4rem,10vw,3.4rem);color:var(--ink);line-height:.9;letter-spacing:-0.02em;font-variant-numeric:tabular-nums;}
  .bio .stat .l{font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-2);margin-top:0;line-height:1.35;}  /* label beside the number; ink-2 for AA contrast */

  /* ===== who for ===== */
  .whofor__text{margin:0 0 clamp(20px,3vh,28px);}
  .whofor__pq{margin:0;}

  /* ===== how it works ===== */
  .how__in .video{aspect-ratio:auto;height:200px;width:100%;margin-top:clamp(22px,3.2vh,30px);}
  /* polish the placeholder caption: swap raw "...To come." for an intentional "Coming soon" (mobile-only, desktop markup untouched) */
  .video .vl{font-size:0;letter-spacing:0;}
  .video .vl::after{content:"Coming soon";font-size:12px;letter-spacing:.16em;color:var(--ink-2);}

  /* ===== cta + footer (dark section — text must be light) ===== */
  .cta h2{color:var(--on-dark);}
  .cta .lead{color:var(--on-dark-2);}
  .cta .eyebrow{color:#C79A5E;}
  .cta__inner{display:block;}
  .cta__intro [data-advance]{display:none;}
  .cta__form{margin-top:clamp(34px,5vh,50px);}
  .cta__fields{gap:var(--s3);margin-top:var(--s3);}
  .field input,.field textarea{font-size:16px;min-height:44px;padding:12px 0;}
  .field textarea{min-height:96px;}
  .cta .btn{min-height:46px;width:auto;}
  .cta__footer{margin-top:clamp(36px,5vh,52px);}
  .foot{flex-direction:column;align-items:flex-start;gap:var(--s3);}
  .foot__links{gap:2px 18px;}
  .foot__links a{display:inline-flex;align-items:center;min-height:44px;padding:4px 0;}  /* 44px touch target on mobile (was 24px) */
  .foot__base{flex-direction:column;align-items:flex-start;gap:6px;}
}

/* ---- MOBILE SCROLL-REVEAL: elements fade + rise as they enter view (class added by JS, mobile only) ---- */
.m-reveal{opacity:0!important;transform:translateY(16px)!important;
  transition:opacity .5s cubic-bezier(.16,1,.3,1),transform .55s cubic-bezier(.16,1,.3,1);}
.m-reveal.m-in{opacity:1!important;transform:none!important;}

/* ===== SECTION CONTRAST (mobile-only): alternate warm panels so each section reads as its own block ===== */
@media(max-width:680px){
  /* solid warm panels (the dot-texture sits ABOVE them via ::before, so no translucency/dimming) */
  .htrack > section.hero--bold,
  .htrack > section.merge,
  .htrack > section.whofor{background:var(--paper);}
  .htrack > section.feature,
  .htrack > section.bio,
  .htrack > section.alt{background:var(--paper-3);}
  /* crisp 1px warm seam at every section boundary below the hero */
  .htrack > section.feature,
  .htrack > section.merge,
  .htrack > section.bio,
  .htrack > section.whofor,
  .htrack > section.alt{border-top:1px solid var(--hairline);}
}

/* Reduced-motion: the mobile hero intro animations are suppressed, so guarantee the hero is visible (not stuck at opacity:0) */
@media (max-width:680px) and (prefers-reduced-motion:reduce){
  html.js .hero__name,
  html.js .hero__above,
  html.js .hero__h2,
  html.js .hero__more,
  html.js .hero__scroll{opacity:1!important;animation:none!important;transform:none!important;}
  /* the absolute poster name must keep its centring transform even with motion off */
  html.js .hero--bold > .hero__name{transform:translateX(-50%)!important;}
  /* bio FLIP is skipped under reduced-motion -> show photo + copy + stats statically (stats are otherwise stage-gated) */
  html.js .bio__text,
  html.js .bio__stats{opacity:1!important;animation:none!important;transform:none!important;}
  html.js .bio__img{opacity:1!important;animation:none!important;transform:scale(1.15)!important;}   /* keep the zoom under reduced motion too */
}

/* ===== MOBILE BACKGROUND: organic flowing line-field (per-section canvas, drawn by main.js) that PARALLAXES on scroll = depth. Canvas sits above the solid panel, below content. ===== */
@media(max-width:680px){
  .htrack > section.hero--bold,
  .htrack > section.feature,
  .htrack > section.merge,
  .htrack > section.whofor,
  .htrack > section.alt,
  .htrack > section.cta{position:relative;overflow:hidden;}
  .bgwave{position:absolute;left:0;top:-120px;width:100%;height:auto;z-index:0;pointer-events:none;will-change:transform;}
  /* keep section content above the texture (but not the canvas itself) */
  .htrack > section.hero--bold > *:not(.bgwave),
  .htrack > section.feature > *:not(.bgwave),
  .htrack > section.merge > *:not(.bgwave),
  .htrack > section.whofor > *:not(.bgwave),
  .htrack > section.alt > *:not(.bgwave),
  .htrack > section.cta > *:not(.bgwave){position:relative;z-index:1;}
}

/* QA: expand the breadcrumb back-link tap area to ~44px without shifting layout */
@media(max-width:680px){
  .phero__crumb a{display:inline-block;padding:14px 6px;margin:-14px -6px;}
}
