/* ===========================================================================
   TT_Header_Tint_CSS — v2.2.0
   Tư-Trà · adaptive header tint + WCAG-aware foreground
   Author: Tư Trà (with Claude)

   Paste into the Bricks Code element's CSS box (header template).
   Companion: TT_Header_Tint_JS v2.6.0

   WHAT THIS FILE DOES (and deliberately does NOT do)
   - It does NOT draw the backdrop gradient. Your Header Appearance CSS owns
     the backdrop and its gradient, which reads
     rgba(var(--color-the-rgb), <stop alpha>). This file leaves that alone.
   - The JS drives the gradient COLOR by overriding --color-the-rgb (tweened
     frame-by-frame for a smooth fade). When no signal section is under the
     sentinel line, the JS removes that override, so your Appearance gradient
     falls back to its own default — untouched.
   - For image sections (data-tt-header-transparent) the JS sets
     --tt-header-bg-opacity to 0; .tt-header-bg-adaptive consumes it and
     fades out, revealing the image through the header.
   - FOREGROUND: the JS injects a forced color rule onto .tt-header-fg-adaptive
     (and its a/button/svg descendants) with !important, because a plain class
     loses to Bricks's own nav color rules. This file therefore does NOT set
     color/fill/stroke on that class — it only provides a smooth transition.
     The logo is driven separately by the header coordinator (not this class).

   SETUP
   - Tag the backdrop element with class "tt-header-bg-adaptive".
   - Tag nav text containers and the hamburger toggle with
     "tt-header-fg-adaptive". Do NOT tag the logo (the coordinator owns it).
   - Tag tinting sections with "tt-header-signal"; image sections also get
     data-tt-header-transparent + a representative background-color.

   EDIT THESE
   - --tt-header-fg-light / --tt-header-fg-dark : the two foreground
     candidates (used by the JS for contrast). Set to your brand colors.

   CHANGELOG
   v2.2.0 — .tt-header-fg-adaptive no longer sets color/fill/stroke (the JS
            now forces those past Bricks via an injected rule). This class
            keeps only a color/fill transition for smoothness. Removed the
            stroke declaration that was mis-coloring the logo outline.
   v2.1.0 — Foreground class renamed; added .tt-header-bg-adaptive for the
            transparent state; no id selectors.
   v2.0.0 — Companion CSS no longer draws the gradient.
   =========================================================================== */

:root{
  /* Adaptive foreground candidates (read by the JS to choose the higher-
     contrast option against each section's background-color). */
  --tt-header-fg-light: #e9d8c8;   /* cream */
  --tt-header-fg-dark:  #62704d;   /* near-black */
}

/* The backdrop element. The JS sets --tt-header-bg-opacity to 0 for image
   sections; this element consumes it and fades out. Defaults to 1 (visible)
   when the var is unset, so your Appearance gradient shows normally. */
.tt-header-bg-adaptive{
  opacity: var(--tt-header-bg-opacity, 1);
  transition: opacity 600ms cubic-bezier(.4, 0, .2, 1);
}

/* Foreground transition only. The actual color is forced by the JS via an
   injected !important rule (a bare class can't beat Bricks's nav color).
   This rule just makes the change ease over 600ms. It does NOT set stroke —
   the logo is colored by the coordinator as fill:currentColor, not here. */
.tt-header-fg-adaptive,
.tt-header-fg-adaptive a,
.tt-header-fg-adaptive button,
.tt-header-fg-adaptive svg{
  transition: color 600ms cubic-bezier(.4, 0, .2, 1),
              fill  600ms cubic-bezier(.4, 0, .2, 1);
}
/* ===========================================================================
   TT_Header_Tint_JS — v2.7.0
   Tư-Trà · adaptive header tint + WCAG-aware foreground
   Author: Tư Trà (with Claude)

   Paste into the Bricks Code element's JavaScript box (Bricks auto-wraps
   it in <script> tags). Companion: TT_Header_Tint_CSS v2.1.0

   MODEL
   ONE sentinel line lives inside the header. Each scroll frame we ask:
   which signal sections (.tt-header-signal) currently SPAN that line?
   Of those, the topmost in z-order wins. The script then:
     - overrides --color-the-rgb with that section's color as an "R, G, B"
       triple, so your Header Appearance gradient re-renders in that color;
     - sets --tt-header-fg to the higher-WCAG-contrast foreground candidate
       (measured against the section's solid background-color);
     - for a section flagged data-tt-header-transparent, sets
       --tt-header-bg-opacity to 0; the element you tag with
       .tt-header-bg-adaptive consumes it and fades out, so an image
       background shows through.
   When NO signal section is under the line, the script REMOVES all of its
   overrides, so the header falls back to your Appearance CSS untouched.

   SETUP
   1. Header wrapper gets the class/selector in HEADER_SELECTOR.
   2. The backdrop element gets class "tt-header-bg-adaptive" (it fades
      out for transparent sections — no id is hardcoded in the JS).
   3. Each tinting section gets class "tt-header-signal".
   4. Image sections also get  data-tt-header-transparent  AND a
      background-color matching the image's dominant tone (foreground
      contrast is measured against background-color, not image pixels).
   5. Header text/icons/SVG that must stay legible get
      "tt-header-fg-adaptive".

   CHANGELOG
   v2.7.0 — Foreground color now fades smoothly: it is interpolated in JS
            (rAF) and written into the forced rule each frame, because a
            CSS transition does not fire reliably on an !important value that
            arrives via a stylesheet swap. Default sentinel position set to
            "middle".
   v2.6.0 — Foreground now FORCED past Bricks via an injected <style> rule
            targeting .tt-header-fg-adaptive and its a/svg descendants with
            !important (a bare class lost on specificity — that's why nav +
            hamburger never changed). After forcing the nav color the script
            calls coordinator.syncNavColor() so the logo follows as `color`
            (the logo uses fill:currentColor; no stroke is applied). Bricks's
            own color remains the fallback when the rule is emptied (no
            signal). The CSS companion's .tt-header-fg-adaptive no longer
            sets stroke/fill — JS owns the forcing now.
   v2.5.0 — (1) Smooth background color fade: the RGB triple is now
            interpolated frame-by-frame over FADE_MS (rAF), since a plain
            triple can't be CSS-transitioned. Your gradient CSS is untouched.
            (2) Foreground now handed to the coordinator (window.TT_HEADER)
            so nav text, logo, and hamburger all follow — instead of relying
            on a CSS class the more-specific Bricks rules were overriding.
            The script probes for a coordinator setter and falls back to
            setting --tt-header-fg; the HUD reports which path was used.
   v2.4.0 — Fixed silent no-op: HEADER_SELECTOR default is now "#brx-header"
            (Bricks's header id); the script waits for DOMReady before
            running; and the debug HUD is built BEFORE the header lookup so
            a missing/mismatched header shows "header: NOT FOUND" instead of
            dying silently. Matches the proven TT_Header_Hold HUD pattern.
   v2.3.1 — Debug parameter renamed ttdebug=1 → tthtint=1 to avoid colliding
            with another module already using ttdebug. DEBUG_PARAM const
            added so the trigger word is easy to change.
   v2.3.0 — Debug now activates via a URL parameter — no code edit needed to
            toggle, and zero overhead in production when absent. The
            FORCE_DEBUG const still works as a manual force-on override.
   v2.2.0 — Added on-screen debug HUD (DEBUG=true): shows signal-section
            count, active section, the color read, the resolved RGB triple,
            transparent flag, and sentinel position. Helps diagnose setup.
   v2.1.0 — Background transparency now driven via --tt-header-bg-opacity
            (consumed by .tt-header-bg-adaptive) instead of selecting the
            backdrop element by id — JS no longer hardcodes a backdrop
            selector. Foreground class renamed .tt-header-adaptive →
            .tt-header-fg-adaptive (CSS-side; JS unaffected by that rename).
   v2.0.0 — Reworked: drives the existing Appearance gradient by overriding
            --color-the-rgb (R,G,B triple) instead of drawing its own
            gradient; transparency via backdrop opacity; no-signal clears
            all overrides so Appearance CSS shows through. No @property /
            relative-color dependency (older-Safari friendly). Color switch
            is instant; opacity + foreground still animate via CSS.
   =========================================================================== */
(function(){
  "use strict";

  function boot(){

  /* ─── CONFIG — EDIT THESE ──────────────────────────────────────────────── */

  /* Header wrapper selector (where the sentinel line is injected). */
  var HEADER_SELECTOR = "#brx-header";

  /* The CSS variable your Appearance gradient reads for its color
     (an "R, G, B" triple). The script overrides this per section. */
  var RGB_VAR = "--color-the-rgb";

  /* Class on page sections whose background should tint the header. */
  var SIGNAL_CLASS = "tt-header-signal";

  /* Attribute that makes a section's backdrop go fully transparent. */
  var TRANSPARENT_ATTR = "data-tt-header-transparent";

  /* Where the sentinel line sits, measured DOWN FROM THE HEADER TOP:
       "top"    → header top edge
       "middle" → header vertical center
       "bottom" → header bottom edge          (the natural choice)
       "<n>%"   → percentage of header height, e.g. "75%"
       "<n>px"  → fixed pixels from header top, e.g. "60px"           */
  var SENTINEL_POS = "middle";

  /* Two foreground candidates for .tt-header-fg-adaptive elements. Each may
     be any CSS color OR a CSS variable. Higher WCAG contrast wins. */
  var FG_LIGHT = "var(--tt-header-fg-light)";
  var FG_DARK  = "var(--tt-header-fg-dark)";

  /* Background color fade duration (ms). The gradient color is a plain RGB
     triple that CSS can't transition, so the script tweens it via rAF. */
  var FADE_MS = 600;

  /* The class you put on elements that must take the adaptive foreground
     (nav UL / links, hamburger toggle). The script forces color onto this
     class and its a/svg descendants, beating Bricks's own color rules. */
  var FG_CLASS = "tt-header-fg-adaptive";

  /* The header coordinator (window[COORDINATOR]). After the script forces
     the nav color, it calls coordinator.syncNavColor() so the logo — which
     the coordinator owns — re-reads and follows. The logo is NOT tagged
     with FG_CLASS; it is driven only through the coordinator. */
  var COORDINATOR = "TT_HEADER";

  /* Debug activation. Add  ?tthtint=1  (or &tthtint=1) to the page URL to
     turn on the magenta sentinel bar, the on-screen HUD, and the WCAG-AA
     console warning. Named uniquely so it does not clash with other TT
     modules' debug params. Off otherwise — zero overhead in production.
     Set FORCE_DEBUG true to force it on regardless of the URL. */
  var DEBUG_PARAM = "tthtint";   // URL param that switches debug on
  var FORCE_DEBUG = false;
  var DEBUG = FORCE_DEBUG ||
    new RegExp("[?&]" + DEBUG_PARAM + "=1(?:&|$)").test(window.location.search);

  /* ─── CSS property names (match the companion CSS) ─────────────────────── */
  var BG_OPACITY_PROP = "--tt-header-bg-opacity";

  /* ─── INIT ─────────────────────────────────────────────────────────────── */
  var root = document.documentElement;

  /* ─── DEBUG HUD ─────────────────────────────────────────────────────────
     A small fixed panel showing what the script sees. Created only when
     DEBUG is true; zero footprint in production. */
  var hud = null;
  function ensureHud(){
    if (!DEBUG || hud) return;
    hud = document.createElement("div");
    hud.setAttribute("aria-hidden", "true");
    hud.style.cssText =
      "position:fixed;left:8px;bottom:8px;z-index:99999;max-width:80vw;" +
      "background:rgba(0,0,0,.85);color:#0f0;font:12px/1.5 monospace;" +
      "padding:8px 10px;border-radius:6px;pointer-events:none;white-space:pre;";
    document.body.appendChild(hud);
  }
  function updateHud(info){
    if (!DEBUG) return;
    ensureHud();
    hud.textContent =
      "TT Header Tint — debug\n" +
      "signal sections found: " + info.count + "\n" +
      "active: " + info.active + "\n" +
      "color read: " + info.color + "\n" +
      "triple set: " + info.triple + "\n" +
      "transparent: " + info.transparent + "\n" +
      "fg: " + info.fg + " via " + fgPath + "\n" +
      "sentinel: " + SENTINEL_POS + "\n" +
      "header: " + (typeof header !== "undefined" && header ? HEADER_SELECTOR + " \u2713" : HEADER_SELECTOR + " NOT FOUND") +
      "  · rgb var: " + RGB_VAR;
  }


  var header = document.querySelector(HEADER_SELECTOR);
  if (!header){
    // Build the HUD even on failure so the problem is visible, not silent.
    updateHud({ count: document.getElementsByClassName(SIGNAL_CLASS).length,
                active: "—", color: "—", triple: "—",
                transparent: false, fg: "—" });
    if (DEBUG) console.warn("[TT_Header_Tint] header not found for selector: " + HEADER_SELECTOR);
    return;
  }

  /* The single sentinel line, pinned inside the header. */
  var sentinel = document.createElement("span");
  sentinel.className = "tt-header-sentinel";
  sentinel.setAttribute("aria-hidden", "true");
  if (getComputedStyle(header).position === "static") header.style.position = "relative";
  header.appendChild(sentinel);

  function placeSentinel(){
    var v = String(SENTINEL_POS).trim().toLowerCase();
    var topCss;
    if (v === "top")        topCss = "0";
    else if (v === "middle") topCss = "50%";
    else if (v === "bottom") topCss = "100%";
    else if (v.slice(-2) === "px") topCss = parseFloat(v) + "px";
    else { var n = parseFloat(v); topCss = (isNaN(n) ? 100 : Math.max(0, Math.min(100, n))) + "%"; }

    if (DEBUG){
      sentinel.style.cssText =
        "position:absolute;left:0;right:0;height:3px;margin-top:-1px;pointer-events:none;" +
        "top:" + topCss + ";background:#ff00d4;box-shadow:0 0 0 1px #fff,0 0 8px #ff00d4;z-index:5;";
    } else {
      sentinel.style.cssText =
        "position:absolute;left:0;width:1px;height:1px;pointer-events:none;top:" + topCss + ";";
    }
  }
  placeSentinel();

  /* Cache the signal sections (their set rarely changes). */
  var sections = [];
  function collectSections(){
    sections = Array.prototype.slice.call(
      document.getElementsByClassName(SIGNAL_CLASS));
  }

  /* Resolve stacking: nearest explicit z-index wins; equal/auto falls back
     to DOM order (later = painted on top), matching the browser. */
  function stackRank(el){
    var node = el;
    while (node && node !== document.body){
      var zi = parseInt(getComputedStyle(node).zIndex, 10);
      if (!isNaN(zi)) return zi;
      node = node.parentElement;
    }
    return 0;
  }

  /* Which section spans the sentinel line; topmost wins. */
  function pick(){
    var lineY = sentinel.getBoundingClientRect().top;
    var best = null, bestZ = -Infinity, bestOrder = -1;
    for (var i = 0; i < sections.length; i++){
      var r = sections[i].getBoundingClientRect();
      if (r.top <= lineY && r.bottom >= lineY){
        var z = stackRank(sections[i]);
        if (z > bestZ || (z === bestZ && i > bestOrder)){
          best = sections[i]; bestZ = z; bestOrder = i;
        }
      }
    }
    return best;
  }

  /* ─── Adaptive foreground (WCAG contrast) ──────────────────────────────── */

  /* Resolve any color string (incl. var(--x)) to [r,g,b] 0–255 by letting
     the browser parse it on a hidden probe element. */
  var probe = document.createElement("span");
  probe.style.cssText = "position:absolute;left:-9999px;width:0;height:0;";
  document.body.appendChild(probe);
  function toRGB(colorStr){
    probe.style.color = "";
    probe.style.color = colorStr;
    var c = getComputedStyle(probe).color;
    var m = c.match(/\d+(\.\d+)?/g);
    return m ? [ +m[0], +m[1], +m[2] ] : [0, 0, 0];
  }
  function toTriple(colorStr){
    var r = toRGB(colorStr);
    return r[0] + ", " + r[1] + ", " + r[2];   // "R, G, B" for --color-the-rgb
  }

  /* ─── Background color interpolation ───────────────────────────────────
     A plain RGB triple cannot be CSS-transitioned, so we tween it ourselves
     with rAF and write each intermediate triple to RGB_VAR. easeInOutCubic
     matches the cubic-bezier(.4,0,.2,1) feel used elsewhere. */
  var curRGB = null;          // current displayed [r,g,b]
  var fadeRAF = null;
  function easeInOut(t){ return t < 0.5 ? 4*t*t*t : 1 - Math.pow(-2*t+2, 3)/2; }
  function setTripleNow(rgb){
    root.style.setProperty(RGB_VAR, Math.round(rgb[0]) + ", " + Math.round(rgb[1]) + ", " + Math.round(rgb[2]));
  }
  function fadeTo(targetRGB){
    if (fadeRAF){ cancelAnimationFrame(fadeRAF); fadeRAF = null; }
    if (!curRGB){ curRGB = targetRGB.slice(); setTripleNow(curRGB); return; }
    var fromRGB = curRGB.slice();
    var start = null;
    function step(ts){
      if (start === null) start = ts;
      var t = Math.min(1, (ts - start) / FADE_MS);
      var e = easeInOut(t);
      var now = [
        fromRGB[0] + (targetRGB[0] - fromRGB[0]) * e,
        fromRGB[1] + (targetRGB[1] - fromRGB[1]) * e,
        fromRGB[2] + (targetRGB[2] - fromRGB[2]) * e
      ];
      setTripleNow(now);
      curRGB = now;
      if (t < 1){ fadeRAF = requestAnimationFrame(step); }
      else { curRGB = targetRGB.slice(); fadeRAF = null; }
    }
    fadeRAF = requestAnimationFrame(step);
  }

  /* ─── Foreground: forced style rule + coordinator sync ─────────────────
     A bare class loses to Bricks's more-specific nav color rules (confirmed
     by inspecting: disabling Bricks's rule let the class through). So we
     inject ONE <style> rule that forces color on .tt-header-fg-adaptive and
     its a/svg descendants with !important. Coloring descendants matters —
     nav text is inside child <a>s and the hamburger icon is an inner <svg>,
     so coloring only the tagged container wouldn't reach them.

     The logo is handled separately: after forcing the nav color we call
     coordinator.syncNavColor(), and the coordinator re-reads the nav's
     computed color and propagates it to the logo (which uses
     fill:currentColor). No stroke, no direct logo manipulation. */
  var fgPath = "init";   // for the HUD
  var fgStyle = document.createElement("style");
  fgStyle.id = "tt-header-fg-rule";
  document.head.appendChild(fgStyle);

  function writeFgRule(rgb){
    var sel = "." + FG_CLASS;
    var c = "rgb(" + Math.round(rgb[0]) + ", " + Math.round(rgb[1]) + ", " + Math.round(rgb[2]) + ")";
    fgStyle.textContent =
      sel + ", " + sel + " a, " + sel + " button, " + sel + " svg {" +
      " color:" + c + " !important; fill:" + c + " !important; }";
  }
  function syncCoordinator(){
    var coord = window[COORDINATOR];
    if (coord && typeof coord.syncNavColor === "function"){ coord.syncNavColor(); return true; }
    return false;
  }

  /* Foreground interpolation. A CSS transition won't fire on an !important
     value injected via a stylesheet swap, so we tween the color ourselves
     and rewrite the rule each frame — then sync the coordinator so the logo
     follows. easeInOut matches the cubic-bezier feel used elsewhere. */
  var curFg = null;       // current displayed [r,g,b], or null when cleared
  var fgFadeRAF = null;
  function fgFadeTo(targetRGB){
    if (fgFadeRAF){ cancelAnimationFrame(fgFadeRAF); fgFadeRAF = null; }
    if (!curFg){ curFg = targetRGB.slice(); writeFgRule(curFg); syncCoordinator(); return; }
    var fromRGB = curFg.slice();
    var start = null;
    function step(ts){
      if (start === null) start = ts;
      var t = Math.min(1, (ts - start) / FADE_MS);
      var e = easeInOut(t);
      var now = [
        fromRGB[0] + (targetRGB[0] - fromRGB[0]) * e,
        fromRGB[1] + (targetRGB[1] - fromRGB[1]) * e,
        fromRGB[2] + (targetRGB[2] - fromRGB[2]) * e
      ];
      writeFgRule(now);
      curFg = now;
      if (t < 1){ fgFadeRAF = requestAnimationFrame(step); }
      else { curFg = targetRGB.slice(); fgFadeRAF = null; syncCoordinator(); }
    }
    fgFadeRAF = requestAnimationFrame(step);
  }

  function pushForeground(rgb){
    fgFadeTo(rgb);
    fgPath = "forced rule (faded)" + (window[COORDINATOR] ? " + syncNavColor" : "");
  }
  function clearForeground(){
    if (fgFadeRAF){ cancelAnimationFrame(fgFadeRAF); fgFadeRAF = null; }
    curFg = null;
    fgStyle.textContent = "";   // empty → Bricks's own color returns
    fgPath = syncCoordinator() ? "cleared + syncNavColor" : "cleared";
  }

  function lum(rgb){
    var a = rgb.map(function(v){
      v /= 255;
      return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
    });
    return 0.2126 * a[0] + 0.7152 * a[1] + 0.0722 * a[2];
  }
  function contrast(c1, c2){
    var l1 = lum(c1), l2 = lum(c2);
    var hi = Math.max(l1, l2), lo = Math.min(l1, l2);
    return (hi + 0.05) / (lo + 0.05);
  }

  function applyForeground(tintStr){
    var bg = toRGB(tintStr);
    var cl = contrast(toRGB(FG_LIGHT), bg);
    var cd = contrast(toRGB(FG_DARK), bg);
    var pickLight = cl >= cd;
    var chosen = pickLight ? FG_LIGHT : FG_DARK;
    // Resolve to concrete RGB so we can interpolate it frame-by-frame.
    pushForeground(toRGB(chosen));
    if (DEBUG && Math.max(cl, cd) < 4.5){
      console.warn("[TT_Header_Tint] Neither foreground clears WCAG AA (4.5:1) on tint " +
        tintStr + " — light " + cl.toFixed(2) + ":1, dark " + cd.toFixed(2) + ":1.");
    }
    return pickLight ? "light" : "dark";
  }

  /* ─── Apply ────────────────────────────────────────────────────────────── */
  /* We only touch the DOM when the active section (or its transparent flag)
     changes. When nothing is active we REMOVE our overrides so the header's
     own Appearance CSS shows through untouched. */
  var lastState = "init";
  var lastFg = "—";
  function apply(){
    var el = pick();
    var color = el ? getComputedStyle(el).backgroundColor : null;
    var transparent = !!(el && el.hasAttribute(TRANSPARENT_ATTR));
    var state = el ? (color + "|" + transparent) : null;

    // HUD reflects current reading on EVERY call, even if nothing changed,
    // so you can scroll and watch live. Built only when DEBUG is true.
    if (DEBUG){
      var label = "none (no section under line)";
      if (el){
        label = (el.id ? "#" + el.id : el.tagName.toLowerCase()) +
                (el.className ? "." + String(el.className).trim().split(/\s+/).join(".") : "");
      }
      updateHud({
        count: sections.length,
        active: label,
        color: color || "—",
        triple: color ? toTriple(color) : "—",
        transparent: transparent,
        fg: lastFg
      });
    }

    if (state === lastState) return;
    lastState = state;

    if (!el){
      // No signal section under the line — clear everything we set so the
      // header's own Appearance CSS shows through untouched.
      if (fadeRAF){ cancelAnimationFrame(fadeRAF); fadeRAF = null; }
      curRGB = null;
      root.style.removeProperty(RGB_VAR);
      root.style.removeProperty(BG_OPACITY_PROP);
      clearForeground();
      lastFg = "—";
      return;
    }

    // Fade the gradient color smoothly to the section's color.
    fadeTo(toRGB(color));
    lastFg = applyForeground(color);

    // Transparent (image) section: drop the backdrop opacity var to 0;
    // .tt-header-bg-adaptive consumes it and CSS gives the 600ms curve.
    // Foreground still contrasts against the section's background-color.
    root.style.setProperty(BG_OPACITY_PROP, transparent ? "0" : "1");
  }

  /* rAF-throttled scroll; nothing runs while idle. */
  var ticking = false;
  function onScroll(){
    if (ticking) return;
    ticking = true;
    requestAnimationFrame(function(){ apply(); ticking = false; });
  }

  collectSections();
  apply();
  window.addEventListener("scroll", onScroll, { passive: true });
  window.addEventListener("resize", function(){
    collectSections(); placeSentinel(); apply();
  }, { passive: true });

  if (window.ResizeObserver){
    var ro = new ResizeObserver(function(){ apply(); });
    ro.observe(header);
  }
  } /* end boot() */

  if (document.readyState === "loading"){
    document.addEventListener("DOMContentLoaded", boot);
  } else {
    boot();
  }
})();

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 
12/1
KHÁM PHÁ THÊM