.passions{
    --ink:#0a0a0a;
    --paper:#ffffff;
    --line-w:2px;
    --tile-w:min(calc(50vw - var(--gap-line)), 900px); /* 2026-08-25 (this
                                        follow-up): per Dakota, desktop tiles
                                        should touch/bleed off the viewport
                                        edge instead of stopping short of it.
                                        The near edge stays at 50% +
                                        --gap-line (unchanged); this formula
                                        makes the FAR edge land exactly at
                                        50% + --gap-line + (50vw -
                                        --gap-line) = 100vw, i.e. the actual
                                        viewport edge. Capped at 900px so
                                        growth (and therefore edge-touching)
                                        stops once the viewport is wider than
                                        an ordinary desktop monitor (cap
                                        engages ~1956px, just past 1920x1080)
                                        — prevents oversized tiles on
                                        ultrawide/4K screens, where the tile
                                        goes back to floating short of the
                                        edge. Mobile (≤820px) is explicitly
                                        reverted to the prior min(44.4vw,
                                        550px) sizing in the media query
                                        below — this change is desktop-only.
                                        Was min(44.4vw, 550px) (13th
                                        follow-up, matched to the real SR
                                        export's literal tile size).        */
    --tile-aspect:11 / 12;          /* portrait, ~0.92. 2026-08-23 8th
                                        follow-up: reverted a same-day attempt
                                        to raise this to 1.02 (shorter frame)
                                        — Dakota wants tile SIZE unchanged;
                                        "title sits higher beside the frame"
                                        is achieved purely via
                                        TITLE_FRACTION_ENTER in the parallax
                                        script, not via tile dimensions. If
                                        this ratio is ever changed again,
                                        also update the hardcoded "* 12 / 11"
                                        divisor in the .row height calc()
                                        below — aspect-ratio shorthand can't
                                        be referenced inside calc().          */
    --gap-line:min(4vw, 76px);      /* tile near-edge distance from line.
                                        2026-09-01: capped — this used to be
                                        an unbounded 4vw, so on very wide
                                        screens the gap between the two
                                        columns (and therefore the whole
                                        module) kept growing with no upper
                                        bound, even though each tile's own
                                        width already capped at 900px via
                                        --tile-w. Capped at 76px (4vw of
                                        ~1900px) so both stop growing
                                        together, matching where --tile-w's
                                        900px cap engages.                   */
    --title-drop:110px;             /* title top = tile top + this. Reverted
                                        to its original 110px (2026-08-23 8th
                                        follow-up; had briefly been 80px in
                                        the same-day 7th follow-up, paired
                                        with a --tile-aspect change that was
                                        also reverted). 2026-08-25 ELEVENTH
                                        FOLLOW-UP: this is once again the
                                        ONLY thing controlling title
                                        position — the JS parallax no longer
                                        touches titles at all (reverted to
                                        the true native SR behavior; see
                                        script section 1).                  */
    --mask-pad-y:60px;              /* white cut above/below title text       */
    --mask-overlap:24px;            /* white box extends past line            */
    --title-clear:30px;             /* text clearance inside mask (line side) */
    --row-gap:200px;                 /* clearance after tile before next row —
                                        row height derives from this so module
                                        length always matches real content;
                                        increased a lot again 2026-08-23 5th
                                        follow-up per Dakota (was 115px, then
                                        84px, then 48px pre-v4)               */
    --stage-top-gap:20px;            /* space between the kicker and the
                                        STAGE (i.e. the top of the black
                                        line) only — kept small on purpose
                                        (2026-08-23 4th follow-up) so the
                                        line stays visually close to "Our
                                        Passions"; the *first row's* extra
                                        drop below that (see --fashion-drop)
                                        is what creates the larger visual
                                        gap before the Fashion frame          */
    --intro-duration:750ms;          /* was 900ms, before that 2000ms, 1200ms,
                                        600ms pre-refinement; decreased to
                                        750ms 2026-08-23 5th follow-up        */
    --tile-fade-duration:300ms;      /* 2026-08-25: video tiles now fade in on
                                        their own faster timer, independent of
                                        --intro-duration (titles/kicker/line
                                        unchanged) — per Dakota, tiles were
                                        fading in too slowly on scroll.      */
    --title-fade-duration:380ms;     /* 2026-08-27: row titles now fade in on
                                        their own faster timer too, on the
                                        same quick --ease-reveal curve as the
                                        video tiles (kicker/line still use
                                        --intro-duration) — per Dakota, titles
                                        were reading as slower than the tile
                                        they sit beside. Paired with a small
                                        animation-delay below so the title
                                        now lands just a beat AFTER the tile
                                        (direction reversed from the prior
                                        tile-behind-title timing).           */
    --ease-reveal:cubic-bezier(0.165, 0.84, 0.44, 1);        /* Power4.easeOut */
    --ease-dark-hold:cubic-bezier(0.755, 0.05, 0.855, 0.06); /* easeInQuint —
                                        one continuous curve: stays dim, then
                                        rises smoothly, no interior kink.
                                        Drives OPACITY only as of the 6th
                                        follow-up — see --ease-move.         */
    --ease-move:cubic-bezier(0.16, 1, 0.3, 1);   /* easeOutExpo-ish — decelerates
                                        smoothly all the way to a stop.
                                        2026-08-23 6th follow-up: the Y-rise
                                        used to share --ease-dark-hold with
                                        opacity, which holds near-still then
                                        snaps to final position at nearly full
                                        speed right as the animation ends —
                                        that abrupt stop read as a "harsh
                                        landing." Now the move animates on
                                        its own smooth ease-out curve while
                                        opacity keeps the liked dark-hold.   */
    --title-rise-y:60px;             /* fade-up Y start offset — was 24px (5th
                                        follow-up), too subtle; SR original
                                        was 200px, too dramatic. 60px reads
                                        as a real rise without "flying up."  */
  }
  :where(.passions), :where(.passions) *{box-sizing:border-box;margin:0;padding:0}
  /* 2026-08-27: html,body background/color removed — this module now shares
     the live page with other shortcode modules, and a global html,body rule
     repaints the ENTIRE page (every module), not just this one. All of this
     module's own styling now lives on .passions itself, which is already
     guaranteed a real background per the note below. */
  .passions{
    font-family:'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    color:var(--ink) !important;
    overflow-x:hidden;
  }

  /* ---------- module shell ---------- */
  /* 2026-08-25: explicit background on the module root itself, not just
     html/body. When this file is embedded as a fragment into the live site
     (rather than loaded as its own standalone document), the site's own
     page background shows through instead of this file's html/body rule —
     that's why the module was rendering black on the live page. Setting the
     background directly on .passions guarantees a real white module
     background no matter what page it's dropped into.                    */
  .passions{position:relative;padding-top:48px;background:var(--paper) !important}
  .passions__kicker{
    font-weight:600;font-size:17px;line-height:48px;
    letter-spacing:.32em;text-transform:uppercase;text-align:center;
    padding-left:.32em; /* optically recenter tracked text */
  }
  .passions__stage{position:relative;margin-top:var(--stage-top-gap)}

  /* single continuous hairline — cut visually by the titles' white boxes.
     Entrance is a downward wipe (clip-path grows top->bottom), matching the
     original SR build's line mask, not a plain opacity fade. */
  .passions__line{
    position:absolute;top:0;bottom:0;left:50%;
    width:var(--line-w);margin-left:calc(var(--line-w) / -2);
    background:var(--ink) !important;z-index:1;
    clip-path:inset(0 0 0% 0);
    -webkit-clip-path:inset(0 0 0% 0);
  }
  /* Visible by default; only hidden pending the reveal animation once we know
     JS actually ran (see html.js-ready note in <head>). */
  html.js-ready .passions__line{
    clip-path:inset(0 0 100% 0);
    -webkit-clip-path:inset(0 0 100% 0);
  }
  @keyframes line-reveal{
    0%   { clip-path:inset(0 0 100% 0); -webkit-clip-path:inset(0 0 100% 0); }
    100% { clip-path:inset(0 0 0% 0);   -webkit-clip-path:inset(0 0 0% 0); }
  }
  .passions__line.is-in{
    animation:line-reveal var(--intro-duration) var(--ease-dark-hold) forwards;
  }

  /* ---------- entrance: 50% speed + held dim (refined 2026-08-23) ----------
     SR base keyframe was opacity 0/Y+200px -> 1/Y0 over 600ms Power4.easeOut.
     Per Dakota: run at half speed (1200ms). The dark-hold now comes from ONE
     continuous easeInQuint-style timing function (--ease-dark-hold) across a
     single 0%->100% keyframe, instead of an interior 65% keyframe stop — that
     interior stop caused a visible kink/pause where the slope suddenly
     changed. easeInQuint holds a low value for most of the duration and only
     accelerates near the end, giving the same "stays dim much longer" feel
     with a perfectly smooth, uninterrupted curve. Titles/kicker/line keep
     the Y rise (.fade-up); video tiles fade in place with no Y offset
     (.fade-in). */
  /* 2026-08-23 6th follow-up: split into two independently-timed animations
     so the Y-move can ease out smoothly (no more harsh, abrupt stop) while
     opacity keeps its own longer dark-hold curve. Both run for the same
     --intro-duration and start at the same instant, they just accelerate/
     decelerate differently. */
  @keyframes enter-rise-move{
    0%   { transform:translateY(var(--title-rise-y)); }
    100% { transform:translateY(0); }
  }
  @keyframes enter-rise-opacity{
    0%   { opacity:0; }
    100% { opacity:1; }
  }
  @keyframes enter-fade{
    0%   { opacity:0; }
    100% { opacity:1; }
  }
  /* Visible by default; only hidden pending reveal once html.js-ready is set. */
  html.js-ready :where(.passions) .fade-up{ opacity:0; transform:translateY(var(--title-rise-y)); }
  .fade-up.is-in, .row.is-inview .fade-up{
    animation:
      enter-rise-opacity var(--intro-duration) var(--ease-dark-hold) forwards,
      enter-rise-move var(--intro-duration) var(--ease-move) forwards;
  }
  /* Visible by default; only hidden pending reveal once html.js-ready is set. */
  html.js-ready :where(.passions) .fade-in{ opacity:0; }
  .fade-in.is-in, .row.is-inview .fade-in{
    /* 2026-08-25: switched from --intro-duration/--ease-dark-hold to a
       dedicated, shorter --tile-fade-duration on the quick --ease-reveal
       curve (Power4.easeOut) — the dark-hold curve stays dim for most of
       its run and only brightens right at the end, which read as sluggish
       for a video tile appearing on scroll. --ease-reveal rises immediately
       instead, so the tile visibly appears much sooner. Titles/kicker/line
       are untouched (still on --intro-duration/--ease-dark-hold). */
    animation:enter-fade var(--tile-fade-duration) var(--ease-reveal) forwards;
  }
  .row__tile.fade-in{ animation-delay:0ms; } /* 2026-08-27: tile now leads (was 60ms behind its title) — titles carry the small delay now, see .row__title-text.fade-up below */

  /* Row titles: dedicated faster reveal that lands just a tad behind the
     tile, reversing the old tile-behind-title order. Overrides the shared
     .fade-up timing above via higher selector specificity — kicker/line are
     untouched and still run on --intro-duration/--ease-dark-hold. */
  .row__title-text.fade-up.is-in,
  .row.is-inview .row__title-text.fade-up{
    animation:
      enter-rise-opacity var(--title-fade-duration) var(--ease-reveal) forwards,
      enter-rise-move var(--title-fade-duration) var(--ease-move) forwards;
    animation-delay:70ms;
  }

  /* ---------- rows ----------
     Height is derived from real tile geometry (tile-top offset + the tile's
     actual rendered height + --row-gap) instead of a guessed vh fraction.
     This keeps row/module length correct on any screen — no leftover empty
     space when the vw-based tile is smaller relative to viewport height (the
     old fixed-vh mobile bug) — and tightens the rhythm so two rows are
     always at least partly visible together, like the source photos. */
  .row{
    /* --fashion-drop (0px on every row except Fashion) must be included here
       too, or the row box is too short to contain a tile that's been pushed
       down by it, and the tile overlaps the next row (2026-08-23 4th
       follow-up fix). */
    position:relative;cursor:pointer;
    height:calc(var(--tile-top, 7vh) + var(--fashion-drop,0px) + (var(--tile-w) * 12 / 11) + var(--row-gap));
    min-height:360px;
  }
  .row__tile{
    /* --fashion-drop is unset (0px) on every row except Fashion, which sets
       it inline (2026-08-23 4th follow-up) so its frame's top clears the
       black line's top by a wide, obvious margin instead of nearly lining
       up with it — see :root comment on --stage-top-gap for the full
       rationale. */
    position:absolute;top:calc(var(--tile-top,7vh) + var(--fashion-drop,0px));
    width:var(--tile-w);aspect-ratio:var(--tile-aspect);
    background:#101010;overflow:hidden;z-index:2;
    will-change:transform;
  }
  .row--tile-right .row__tile{left:calc(50% + var(--gap-line))}
  .row--tile-left  .row__tile{right:calc(50% + var(--gap-line))}
  .row__media{width:100%;height:100%}
  .row__tile video{width:100%;height:100%;object-fit:cover;display:block}
  /* 2026-08-23 7th follow-up: the entrance fade now lives on .row__tile
     itself (the whole frame: dark fallback bg + video together), not on the
     inner .row__media div. Previously .row__tile's #101010 background sat
     BEHIND .row__media at full opacity the whole time, so as the video div
     faded from 0→1 it composited against solid opaque black — reading as
     the video "warming up from black" even though it was already playing
     underneath. Fading the whole .row__tile (which has nothing behind it
     but the page's white background) means it composites against
     transparent/white instead — a true fade-from-transparent, with the
     already-playing video simply becoming visible as it goes. */

  /* title: flush against the line, white bg = the "cut" in the line.
     2026-08-23 6th follow-up: the white box must NOT fade with the text —
     it needs to be constant/solid from the start so it reliably cuts the
     line underneath. So the box (background+padding+position) lives on the
     outer .row__title (never animated), while only the text runs the
     fade-up animation via an inner .row__title-text span. */
  .row__title{
    position:absolute;top:calc(var(--tile-top,7vh) + var(--title-drop) + var(--fashion-drop,0px));
    z-index:3;
    font-weight:700;font-size:50px;line-height:50px;
    text-transform:uppercase;letter-spacing:0;
    background:var(--paper) !important;padding:var(--mask-pad-y) 0;
    color:var(--ink) !important;
  }
  .row__title-text{ display:block; }
  .row--tile-right .row__title{             /* title LEFT of line  */
    right:calc(50% - var(--mask-overlap));
    padding-right:var(--title-clear);text-align:right;
  }
  .row--tile-left .row__title{              /* title RIGHT of line */
    left:calc(50% - var(--mask-overlap));
    padding-left:var(--title-clear);text-align:left;
  }

  /* ---------- end spacer + dot-grid ornament (scr 616/617) ----------
     Shortened (2026-08-23 second follow-up) so the next homepage module can
     begin sooner after Music Videos, matching the tightened row rhythm. */
  .passions__end{position:relative;height:18vh;min-height:120px}
  .passions__dots{
    position:absolute;left:calc(50% + 11vw);bottom:4vh;
    width:186px;height:128px;
    background-image:radial-gradient(#cfcfcf 1.7px, transparent 1.7px);
    background-size:19px 19px;
  }

  /* ---------- responsive ---------- */
  @media (max-width:820px){
    .passions{
      --gap-line:5vw;
      --tile-w:min(44.4vw, 550px); /* mobile keeps the prior (non-edge-
                                       touching) sizing — the edge-touch
                                       change above is desktop-only. */
      --title-drop:64px; /* reverted alongside the desktop 110px revert (8th follow-up) */
      --mask-pad-y:34px;
      --mask-overlap:14px;
      --title-clear:16px;
      --row-gap:114px;                 /* scaled from 200px desktop at the
                                          same ~0.57 ratio used elsewhere in
                                          this breakpoint (was 66px, 48px)    */
      --stage-top-gap:12px;            /* scaled down with the desktop value */
    }
    .passions__kicker{font-size:13px;line-height:34px;letter-spacing:.3em}
    .row{min-height:240px}   /* height itself comes from the shared calc()
                                 formula above — no fixed vh override, which
                                 is what removed the empty space at the
                                 bottom of the module on mobile */
    .row__title{font-size:28px;line-height:30px}
    .passions__end{height:12vh;min-height:80px}
    .passions__dots{width:120px;height:84px;background-size:15px 15px;left:calc(50% + 8vw);bottom:3vh}
  }

  @media (prefers-reduced-motion:reduce){
    .fade-up,.fade-in{animation:none !important;opacity:1 !important;transform:none !important}
    .passions__line{animation:none !important;clip-path:inset(0) !important;-webkit-clip-path:inset(0) !important}
  }
