/**
 * Tư-Trà Hero Header Suppress
 *
 * Keeps the header at full size while a "fullsize hero" section is
 * visible above the header. .scrolling only activates once the next
 * section's top crosses the bottom of the header — i.e., the moment
 * the next section actually starts sliding under the sticky header.
 *
 * Usage:
 *   In Bricks Builder, add the CSS class `tt-fullsize-hero` to the
 *   hero section. The script automatically pairs it with the next
 *   sibling section to detect when the hero region ends.
 *
 * Architecture:
 *   - Threshold: next-sibling.rect.top vs header.rect.bottom
 *     > 0  : hero region dominant — suppress .scrolling
 *     <= 0 : next section overlapping header — allow .scrolling
 *
 *   - Synchronous scroll listener (no rAF throttle): runs in the same
 *     event tick as Bricks's handler, so .scrolling is stripped before
 *     the browser paints. No frame-ordering race, no hesitation on iOS
 *     momentum scroll.
 *
 *   - MutationObserver on body + header class attribute: backup for
 *     when Bricks toggles .scrolling outside of scroll events (rAF,
 *     setTimeout, transitionend). Fires as a microtask, before paint —
 *     the briefly-added class is gone before the user sees it.
 *
 *   - Auto-no-op on pages without a hero (early return).
 *   - No CSS changes required.
 *
 * Version: 1.2.0
 * Author: Charlie + Claude
 *
 * History
 * v1.0.0: IntersectionObserver on hero. Broke for sticky heroes —
 *         IO reports the hero as intersecting for its entire stuck
 *         duration because the bounding rect stays at top:0.
 * v1.1.0: Switched to next-sibling rect check. Fixed sticky case.
 *         Worked on desktop, but rAF throttle exposed a frame-ordering
 *         race against Bricks's own rAF on iOS momentum scroll —
 *         visible hesitation when scrolling back to top.
 * v1.2.0: Synchronous scroll handler eliminates the rAF race.
 *         MutationObserver covers Bricks's non-scroll additions of
 *         .scrolling. Threshold raised from y=0 to header.bottom so
 *         shrink begins at the correct visual moment (next section
 *         meeting the header, not crossing the viewport top).
 */
(function () {
  'use strict';

  var HERO_SELECTOR   = '.tt-fullsize-hero';
  var SCROLLING_CLASS = 'scrolling';
  var HEADER_SELECTOR = '#brx-header, header.brxe-header';

  function init() {
    var heroes = document.querySelectorAll(HERO_SELECTOR);
    if (heroes.length === 0) return;

    // Pair each hero with its next sibling. Next sibling acts as the
    // visual signal for "hero region has ended" — works for both
    // sticky and non-sticky heroes.
    var pairs = [];
    for (var i = 0; i < heroes.length; i++) {
      pairs.push({ hero: heroes[i], next: heroes[i].nextElementSibling });
    }

    var headerEls = document.querySelectorAll(HEADER_SELECTOR);
    var heroActive = false;

    function isHeroActive() {
      // Read header bottom each call. The header may itself shrink
      // (changing its height) when .scrolling is on, but we only ever
      // need this measurement at the threshold moment, where the
      // header is still full-size.
      var headerBottom = 0;
      if (headerEls.length > 0) {
        headerBottom = headerEls[0].getBoundingClientRect().bottom;
      }
      for (var j = 0; j < pairs.length; j++) {
        var p = pairs[j];
        var endRef = p.next
          ? p.next.getBoundingClientRect().top
          : p.hero.getBoundingClientRect().bottom;
        if (endRef > headerBottom) return true;
      }
      return false;
    }

    function clearScrolling() {
      if (document.body.classList.contains(SCROLLING_CLASS)) {
        document.body.classList.remove(SCROLLING_CLASS);
      }
      for (var k = 0; k < headerEls.length; k++) {
        headerEls[k].classList.remove(SCROLLING_CLASS);
      }
    }

    function update() {
      heroActive = isHeroActive();
      if (heroActive) clearScrolling();
    }

    // Synchronous scroll listener: no rAF. Runs in the same tick as
    // Bricks's handler; ordering doesn't matter because the
    // MutationObserver below catches any add we miss.
    window.addEventListener('scroll', update, { passive: true });
    window.addEventListener('resize', update);

    // Backup: if anything (Bricks's rAF, a transitionend handler, etc.)
    // adds .scrolling while heroActive, strip it immediately as a
    // microtask, before the next paint.
    var classObserver = new MutationObserver(function () {
      if (heroActive) clearScrolling();
    });
    classObserver.observe(document.body, {
      attributes: true,
      attributeFilter: ['class']
    });
    for (var m = 0; m < headerEls.length; m++) {
      classObserver.observe(headerEls[m], {
        attributes: true,
        attributeFilter: ['class']
      });
    }

    update(); // Handle reload-mid-page
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();

VUỐT LÊN
VÀ KHÁM PHÁ
Dấu ấn

Phong vị Núi cao

Qua từng

TÁCH TRÀ

COMING SOON

Tư-Trà's selection

Ô Long Sữa Rang

49.000 

Ô long Sữa Gạo rang

Ô long Sữa Hoa nhài

Ô long Sữa nguyên vị

Ô Long Sữa Rang khói

49.000 
KHÁM PHÁ THÊM