{
    "generated": "2026-09-02T14:40:02+03:00",
    "source_site": "https://gsap.pinul.com",
    "page": {
        "id": 447,
        "slug": "linden",
        "title": "Linden — scroll cinematic (test)",
        "url": "https://gsap.pinul.com/linden/"
    },
    "requires": {
        "bricks": "2.3.12",
        "wp": "7.1",
        "header_scripts": "<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js\\\"></script>\r\n\r\n\r\n<script src=\\\"https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js\\\" id=\\\"gsap-js-js\\\"></script>\r\n<script src=\\\"https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/ScrollTrigger.min.js?\\\" id=\\\"gsap-st-js\\\"></script>\r\n<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/gsap/3.13.0/SplitText.min.js\\\" integrity=\\\"sha512-wOeEC+9qERAzhliwBFPDb6t8TiFFxdxG8vhK/Ygs7TuC44bpg8pg/X2/U/u+0X4fK05wb9id1EIipnF02+CFQw==\\\" crossorigin=\\\"anonymous\\\" referrerpolicy=\\\"no-referrer\\\"></script>\r\n\r\n\r\n<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/gsap/3.13.0/ScrollSmoother.min.js\\\" ></script>\r\n<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/gsap/3.13.0/Observer.min.js\\\" integrity=\\\"sha512-GdLRoSd7fNE36D+SKii0MOd6MG1kljA09It5wir9Rv6lYYWWYjXQTCtvzvJppbEG0eAGdoavuIxDsDN8pzzD2A==\\\" crossorigin=\\\"anonymous\\\" referrerpolicy=\\\"no-referrer\\\"></script>\r\n<script src=\\\"https://cdnjs.cloudflare.com/ajax/libs/gsap/3.13.0/MotionPathPlugin.min.js\\\" integrity=\\\"sha512-vuNgw6lF+p97XmL9lFpbQZWBXxIFnwUVt7J/uknE4NJru5GJjjhIAauXdDtNdezqOJFnit+M3AeaM+gZ93hlmg==\\\" crossorigin=\\\"anonymous\\\" referrerpolicy=\\\"no-referrer\\\"></script>\r\n\r\n",
        "note": "Theme style sets a 10px rem base on this site; the ported CSS is already in px."
    },
    "page_settings": {
        "bodyClasses": "linden linden-loading",
        "disableLazyLoad": true
    },
    "elements": [
        {
            "id": "lnsec",
            "name": "section",
            "parent": 0,
            "children": [
                "lncode",
                "lncopy",
                "lnnav",
                "lntrack"
            ],
            "settings": {
                "tag": "section",
                "_cssClasses": "lin",
                "_padding": {
                    "top": "0",
                    "right": "0",
                    "bottom": "0",
                    "left": "0"
                }
            },
            "label": "LINDEN"
        },
        {
            "id": "lncode",
            "name": "code",
            "parent": "lnsec",
            "children": [],
            "settings": {
                "code": "<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n<link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css2?family=Cormorant:wght@400;500&display=swap\">\n\n<!-- Loading overlay -->\n<div class=\"lin-loader\" id=\"lin-loader\">\n  <div class=\"lin-loader-mark\">\n    <div class=\"lin-loader-wordmark\">LINDEN</div>\n    <div class=\"lin-loader-hairline\"></div>\n  </div>\n  <img class=\"lin-loader-drawing\" src=\"https://gsap.pinul.com/wp-content/uploads/2026/09/drawing-one.jpg\" alt=\"\" draggable=\"false\">\n</div>\n\n<!-- Fixed media stage. Dual-source <video> is not expressible with the native\n     Bricks video element, so the stage lives here; all copy is native. -->\n<div class=\"lin-stage\" id=\"lin-stage\" aria-hidden=\"true\">\n  <div class=\"lin-panel\" id=\"lin-panel\">\n    <div class=\"lin-media\">\n      <video id=\"lin-v02\" class=\"lin-media-item\" muted playsinline preload=\"auto\" disablepictureinpicture>\n        <source src=\"https://gsap.pinul.com/wp-content/uploads/2026/09/video-02-top-down.webm\" type=\"video/webm\">\n        <source src=\"https://gsap.pinul.com/wp-content/uploads/2026/09/video-02-top-down.mp4\" type=\"video/mp4\">\n      </video>\n      <img id=\"lin-floorplan\" class=\"lin-media-item\" src=\"https://gsap.pinul.com/wp-content/uploads/2026/09/floor-plan.jpg\" alt=\"Floor plan line drawing\" draggable=\"false\">\n      <video id=\"lin-v04\" class=\"lin-media-item\" muted playsinline preload=\"auto\" disablepictureinpicture>\n        <source src=\"https://gsap.pinul.com/wp-content/uploads/2026/09/video-04-top-down-to-three-quarter.webm\" type=\"video/webm\">\n        <source src=\"https://gsap.pinul.com/wp-content/uploads/2026/09/video-04-top-down-to-three-quarter.mp4\" type=\"video/mp4\">\n      </video>\n      <video id=\"lin-v05\" class=\"lin-media-item\" muted playsinline preload=\"auto\" disablepictureinpicture>\n        <source src=\"https://gsap.pinul.com/wp-content/uploads/2026/09/video-05-day-to-night.webm\" type=\"video/webm\">\n        <source src=\"https://gsap.pinul.com/wp-content/uploads/2026/09/video-05-day-to-night.mp4\" type=\"video/mp4\">\n      </video>\n      <video id=\"lin-v06\" class=\"lin-media-item\" muted playsinline preload=\"auto\" disablepictureinpicture>\n        <source src=\"https://gsap.pinul.com/wp-content/uploads/2026/09/video-06-night-to-day.webm\" type=\"video/webm\">\n        <source src=\"https://gsap.pinul.com/wp-content/uploads/2026/09/video-06-night-to-day.mp4\" type=\"video/mp4\">\n      </video>\n    </div>\n  </div>\n</div>\n",
                "language": "html",
                "executeCode": true,
                "noRoot": true,
                "signature": "51187ae18ed42336bb82f9c176105bb4",
                "cssCode": "/* LINDEN — scoped port of the standalone scroll-cinematic site */\n\nbody.linden { background: #F5F1EC; }\nbody.linden #brx-header,\nbody.linden #brx-footer { display: none !important; }\nbody.linden.linden-loading .lin-scroll-track { height: 0; }\n\n.lin {\n  --lin-bg: #F5F1EC;\n  --lin-ink: #1A1A1A;\n  --lin-on-dark: #FFFFFF;\n  --lin-hairline: rgba(26, 26, 26, 0.4);\n  --lin-stroke-soft: rgba(26, 26, 26, 0.3);\n\n  --lin-font: 'Cormorant', 'Cormorant Garamond', Georgia, serif;\n  --lin-tracking-wide: 0.25em;\n\n  --lin-fs-wordmark: clamp(24px, 2vw, 32px);\n  --lin-fs-title: clamp(32px, 3.6vw, 52px);\n  --lin-fs-eyebrow: 12.8px;\n  --lin-fs-body: clamp(16px, 1.15vw, 18.4px);\n  --lin-fs-nav: 13.6px;\n\n  --lin-lh-title: 1.15;\n  --lin-lh-body: 1.7;\n\n  --lin-radius-pill: 999px;\n  --lin-stroke: 1px;\n  --lin-ease-expo: cubic-bezier(0.16, 1, 0.3, 1);\n\n  --lin-gutter: clamp(24px, 5vw, 80px);\n  /* Sections 2-4 copy sits inboard of the gutter, closer to the framed media. */\n  --lin-copy-inset: clamp(24px, 8.5vw, 176px);\n\n  position: relative;\n  display: block;\n  padding: 0;\n  margin: 0;\n  background: var(--lin-bg);\n  color: var(--lin-ink);\n  font-family: var(--lin-font);\n  letter-spacing: 0.01em;\n  -webkit-font-smoothing: antialiased;\n}\n\n.lin *, .lin *::before, .lin *::after { box-sizing: border-box; }\n\n/* ---------- Loader ---------- */\n\n.lin-loader {\n  position: fixed;\n  inset: 0;\n  z-index: 40;\n  background: var(--lin-on-dark);\n  display: flex;\n  align-items: center;\n  justify-content: center;\n}\n\n.lin-loader-mark { text-align: center; }\n\n.lin-loader-wordmark {\n  font-size: var(--lin-fs-wordmark);\n  letter-spacing: var(--lin-tracking-wide);\n  text-indent: var(--lin-tracking-wide); /* optically recentre tracked text */\n  text-transform: uppercase;\n  color: var(--lin-ink);\n  opacity: 0;\n  transform: translateY(8px);\n}\n\n.lin-loader-hairline {\n  margin: 17.6px auto 0;\n  width: 160px;\n  height: 1px;\n  background: var(--lin-hairline);\n  transform: scaleX(0);\n  transform-origin: center;\n}\n\n.lin-loader-drawing {\n  position: absolute;\n  /* Sit in exactly the box .lin-media occupies — inside the panel's stroke — so\n     the handoff to the first video frame lands pixel-on-pixel. */\n  inset: var(--lin-stroke);\n  width: calc(100% - 2 * var(--lin-stroke));\n  height: calc(100% - 2 * var(--lin-stroke));\n  object-fit: cover;\n  opacity: 0;\n}\n\n/* ---------- Fixed stage ---------- */\n\n.lin-stage { position: fixed; inset: 0; z-index: 1; }\n\n.lin-panel {\n  position: absolute;\n  top: 0; left: 0;\n  width: 100%; height: 100%;\n  padding: 0;\n  border: var(--lin-stroke) solid rgba(26, 26, 26, 0);\n  border-radius: 0;\n  /* No will-change here: it does nothing for layout properties and only forces\n     a layer that gets invalidated every frame while the panel resizes. */\n}\n\n.lin-media {\n  position: relative;\n  width: 100%; height: 100%;\n  overflow: hidden;\n  border-radius: 0; /* animated up to 12px */\n  /* Deliberately NOT promoted to its own layer. The box is resized every frame\n     during the two geometry transitions, so a composited layer would have to be\n     re-rastered (mask included) each tick, which shows up as jitter. */\n}\n\n.lin-media-item {\n  position: absolute;\n  inset: 0;\n  width: 100%; height: 100%;\n  object-fit: cover;\n  opacity: 0;\n  display: block;\n}\n\n#lin-v02 { opacity: 1; }\n\n/* ---------- Copy overlays ---------- */\n\n.lin-copy {\n  position: fixed;\n  inset: 0;\n  z-index: 2;\n  display: block;\n  pointer-events: none;\n}\n\n.lin-copy-left {\n  position: absolute;\n  display: block;\n  left: var(--lin-copy-inset);\n  top: 50%;\n  transform: translateY(-50%);\n  width: min(544px, 38vw);\n}\n\n.lin-copy-center {\n  position: absolute;\n  display: block;\n  left: 50%;\n  top: 11vh;\n  transform: translateX(-50%);\n  width: min(736px, 84vw);\n  text-align: center;\n}\n\n.lin-copy-left > *, .lin-copy-center > * { visibility: hidden; }\n\n.lin .lin-eyebrow {\n  font-family: var(--lin-font);\n  font-size: var(--lin-fs-eyebrow);\n  font-weight: 400;\n  letter-spacing: var(--lin-tracking-wide);\n  text-transform: uppercase;\n  line-height: 1.4;\n  color: var(--lin-ink);\n  margin: 0 0 22.4px;\n}\n\n.lin .lin-title {\n  font-family: var(--lin-font);\n  font-size: var(--lin-fs-title);\n  font-weight: 400;\n  line-height: var(--lin-lh-title);\n  color: var(--lin-ink);\n  margin: 0 0 22.4px;\n}\n\n.lin .lin-body,\n.lin .lin-subtext {\n  font-family: var(--lin-font);\n  font-size: var(--lin-fs-body);\n  font-weight: 400;\n  line-height: var(--lin-lh-body);\n  color: var(--lin-ink);\n  margin: 0;\n}\n\n.lin .lin-copy-night .lin-title,\n.lin .lin-copy-night .lin-eyebrow { color: var(--lin-on-dark); }\n.lin .lin-copy-night .lin-title { margin-bottom: 17.6px; }\n.lin .lin-copy-night .lin-eyebrow { margin-bottom: 0; }\n\n#lin-copy-s6 .lin-subtext { max-width: 480px; margin: 0 auto 32px; }\n\n.lin .lin-pill {\n  pointer-events: auto;\n  display: inline-block;\n  font-family: var(--lin-font);\n  font-size: var(--lin-fs-nav);\n  font-weight: 400;\n  letter-spacing: var(--lin-tracking-wide);\n  text-indent: var(--lin-tracking-wide);\n  text-transform: uppercase;\n  color: var(--lin-ink);\n  background: rgba(255, 255, 255, 0.55);\n  border: var(--lin-stroke) solid var(--lin-stroke-soft);\n  border-radius: var(--lin-radius-pill);\n  padding: 0.9em 2.4em;\n  cursor: pointer;\n  transition: background 0.6s var(--lin-ease-expo);\n}\n\n.lin .lin-pill:hover,\n.lin .lin-pill:focus-visible { background: rgba(255, 255, 255, 0.85); }\n\n/* ---------- Nav (static, scrolls away) ---------- */\n\n.lin-nav {\n  position: absolute;\n  top: 0; left: 0; right: 0;\n  z-index: 3;\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n  justify-content: space-between;\n  padding: clamp(25.6px, 3.5vh, 41.6px) var(--lin-gutter) 0;\n  margin: 0;\n  pointer-events: none;\n}\n\n.lin-nav-side {\n  display: flex;\n  flex-direction: row;\n  gap: clamp(19.2px, 2.5vw, 38.4px);\n  flex: 1;\n  padding: 0;\n  margin: 0;\n}\n\n.lin-nav-right { justify-content: flex-end; }\n\n.lin .lin-wordmark {\n  font-family: var(--lin-font);\n  font-size: var(--lin-fs-wordmark);\n  font-weight: 400;\n  letter-spacing: var(--lin-tracking-wide);\n  text-indent: var(--lin-tracking-wide);\n  text-transform: uppercase;\n  color: var(--lin-ink);\n  opacity: 0;\n  margin: 0;\n}\n\n.lin .lin-nav-link {\n  pointer-events: auto;\n  font-family: var(--lin-font);\n  font-size: var(--lin-fs-nav);\n  font-weight: 400;\n  letter-spacing: var(--lin-tracking-wide);\n  text-transform: uppercase;\n  color: var(--lin-ink);\n  background: none;\n  border: none;\n  padding: 0;\n  margin: 0;\n  cursor: pointer;\n  opacity: 0;\n}\n\n/* ---------- Scroll track ---------- */\n\n.lin-scroll-track { height: 700vh; }\n\n/* ---------- Narrow screens ---------- */\n\n@media (max-width: 820px) {\n  .lin-copy-left {\n    top: auto;\n    bottom: 6vh;\n    left: var(--lin-gutter);\n    right: var(--lin-gutter);\n    width: auto;\n    transform: none;\n  }\n  .lin-copy-left .lin-eyebrow { margin-bottom: 14.4px; }\n  .lin-copy-left .lin-title { margin-bottom: 14.4px; }\n}\n\n/* ---------- Reduced motion ---------- */\n\n@media (prefers-reduced-motion: reduce) {\n  .lin-scroll-track { height: 600vh; }\n}\n",
                "javascriptCode": "/* LINDEN — one continuous cinematic scroll sequence.\n   GSAP 3.13 + ScrollTrigger are already loaded site-wide; never enqueue a second copy. */\n(function () {\n  var root = document.querySelector('.lin');\n  if (!root || !window.gsap || !window.ScrollTrigger) return;\n\n  gsap.registerPlugin(ScrollTrigger);\n  gsap.ticker.lagSmoothing(0);\n\n  /* Reserve the scrollbar track from the first paint, so releasing the loader\n     (which restores .lin-scroll-track's height) does not shift the layout. */\n  document.documentElement.style.overflowY = 'scroll';\n\n  var BASE = 'https://gsap.pinul.com/wp-content/uploads/2026/09/';\n  var EXPO = 'expo.out';\n  var INK = 'rgba(26, 26, 26, 1)';\n  var INK_0 = 'rgba(26, 26, 26, 0)';\n\n  var panel = document.getElementById('lin-panel');\n  var media = root.querySelector('.lin-media');\n  var v02 = document.getElementById('lin-v02');\n  var v04 = document.getElementById('lin-v04');\n  var v05 = document.getElementById('lin-v05');\n  var v06 = document.getElementById('lin-v06');\n  var floorplan = document.getElementById('lin-floorplan');\n  var videos = [v02, v04, v05, v06];\n\n  var reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n  history.scrollRestoration = 'manual';\n  window.scrollTo(0, 0);\n\n  /* ---------- Contained panel geometry (Sections 2-4) ---------- */\n\n  /* Background tabs can briefly report a 0x0 viewport; fall back to the last\n     non-zero measurement so scrubbed geometry never collapses. */\n  var lastVW = 1280, lastVH = 800;\n  function viewportW() {\n    var w = document.documentElement.clientWidth;\n    if (w > 0) lastVW = w;\n    return lastVW;\n  }\n  function viewportH() {\n    var h = document.documentElement.clientHeight;\n    if (h > 0) lastVH = h;\n    return lastVH;\n  }\n  viewportW(); viewportH();\n  window.addEventListener('resize', function () { viewportW(); viewportH(); });\n\n  function gutter() {\n    return Math.min(Math.max(24, viewportW() * 0.05), 80);\n  }\n\n  /* Landscape 3:2 frame: wider than the copy needs it to be tall, which pulls the\n     left edge of the media toward the text and closes the gap between them. */\n  var PANEL_ASPECT = 3 / 2;\n\n  function panelRect() {\n    var vw = viewportW(), vh = viewportH(), w, h;\n    if (vw <= 820) {\n      w = Math.min(vw - 2 * gutter(), (vh * 0.44) * PANEL_ASPECT);\n      h = w / PANEL_ASPECT;\n      return { top: Math.round(vh * 0.09), left: Math.round((vw - w) / 2), width: Math.round(w), height: Math.round(h) };\n    }\n    w = Math.min(vw * 0.43, vh * 0.72 * PANEL_ASPECT);\n    h = w / PANEL_ASPECT;\n    return { top: Math.round((vh - h) / 2), left: Math.round(vw - gutter() - w), width: Math.round(w), height: Math.round(h) };\n  }\n\n  /* ---------- Preload: fetch every media file fully so handoffs never pop ---------- */\n\n  function preloadVideo(video) {\n    return new Promise(function (resolve) {\n      var sources = [].slice.call(video.querySelectorAll('source'));\n      var pick = sources.filter(function (s) { return video.canPlayType(s.type); })[0] || sources[0];\n      fetch(pick.src)\n        .then(function (r) { return r.blob(); })\n        .then(function (blob) {\n          video.src = URL.createObjectURL(blob);\n          video.load();\n          var done = function () {\n            video.currentTime = 0.001; // paint the first frame\n            resolve();\n          };\n          if (video.readyState >= 2) done();\n          else video.addEventListener('loadeddata', done, { once: true });\n        })\n        .catch(resolve); // fall back to streaming if fetch fails\n    });\n  }\n\n  function preloadImage(src) {\n    return new Promise(function (resolve) {\n      var img = new Image();\n      img.onload = img.onerror = function () { resolve(); };\n      img.src = src;\n    });\n  }\n\n  var assetsReady = Promise.race([\n    Promise.all(\n      videos.map(preloadVideo).concat([\n        preloadImage(BASE + 'drawing-one.jpg'),\n        preloadImage(BASE + 'floor-plan.jpg'),\n        document.fonts ? document.fonts.ready : Promise.resolve()\n      ])\n    ),\n    new Promise(function (resolve) { setTimeout(resolve, 15000); }) // never trap the user\n  ]);\n\n  /* ---------- Loading screen ---------- */\n\n  var loaderIntro = gsap.timeline();\n  loaderIntro\n    .to('.lin-loader-wordmark', { opacity: 1, y: 0, duration: 1.5, ease: EXPO }, 0.15)\n    .to('.lin-loader-hairline', { scaleX: 1, duration: 1.9, ease: EXPO }, 0.35);\n\n  Promise.all([\n    assetsReady,\n    new Promise(function (resolve) { loaderIntro.eventCallback('onComplete', resolve); })\n  ]).then(runLoaderTransition);\n\n  function runLoaderTransition() {\n    gsap.timeline({ onComplete: function () { setTimeout(startSite, 0); } })\n      .to('.lin-loader-drawing', { opacity: 1, duration: 1.3, ease: 'power2.inOut' }, 0.2)\n      /* Drop the wordmark + hairline while the drawing fully covers them, so the\n         fade-out reveals the site underneath and not the loader mark. */\n      .set('.lin-loader-mark', { autoAlpha: 0 })\n      .set('.lin-loader', { background: 'transparent' })\n      .to('.lin-loader-drawing', { opacity: 0, duration: 1.3, ease: 'power2.inOut' }, '+=0.4')\n      .set('.lin-loader', { display: 'none' })\n      .to('.lin-wordmark', { opacity: 1, duration: 1.4, ease: EXPO })\n      .to('.lin-nav-link', { opacity: 1, duration: 1.4, ease: EXPO }, '-=1.0');\n  }\n\n  function startSite() {\n    document.body.classList.remove('linden-loading');\n    if (reduced) buildReduced();\n    else buildCinematic();\n    ScrollTrigger.refresh();\n  }\n\n  /* ---------- Helpers ---------- */\n\n  function copyEls(id) {\n    return [].slice.call(document.querySelectorAll('#' + id + ' > *'));\n  }\n\n  // Scrub a video's playback across `dur` timeline units at position `pos`.\n  function addVideoScrub(tl, video, pos, dur) {\n    var proxy = { p: 0 };\n    tl.to(proxy, {\n      p: 1,\n      duration: dur,\n      ease: 'none',\n      onUpdate: function () {\n        if (video.duration) video.currentTime = proxy.p * (video.duration - 0.05);\n      }\n    }, pos);\n  }\n\n  // Staggered entrance that completes exactly at `endPos` (a snap label).\n  function textIn(tl, id, endPos, dur) {\n    dur = dur || 0.3;\n    var els = copyEls(id);\n    var each = dur * 0.8;\n    var stagger = dur * 0.18;\n    var total = each + stagger * (els.length - 1);\n    tl.fromTo(els,\n      { autoAlpha: 0, y: 26 },\n      { autoAlpha: 1, y: 0, duration: each, stagger: stagger, ease: EXPO },\n      endPos - total);\n  }\n\n  function textOut(tl, id, pos, dur) {\n    dur = dur || 0.25;\n    tl.to(copyEls(id),\n      { autoAlpha: 0, y: -18, duration: dur * 0.8, stagger: dur * 0.12, ease: 'power2.in' },\n      pos);\n  }\n\n  /* ---------- Full cinematic build ---------- */\n\n  function buildCinematic() {\n    var tl = gsap.timeline({\n      scrollTrigger: {\n        trigger: '.lin-scroll-track',\n        start: 'top top',\n        end: 'bottom bottom',\n        scrub: 1.2,\n        invalidateOnRefresh: true,\n        snap: {\n          snapTo: 'labelsDirectional',\n          duration: { min: 0.5, max: 1.5 },\n          delay: 0.12,\n          ease: 'power3.out'\n        }\n      }\n    });\n\n    window.__lindenMaster = tl;\n\n    tl.addLabel('hero', 0);\n\n    /* Hero -> Section 2: video 02 plays while the frame shrinks to the right */\n    tl.to(panel, {\n      top: function () { return panelRect().top; },\n      left: function () { return panelRect().left; },\n      width: function () { return panelRect().width; },\n      height: function () { return panelRect().height; },\n      padding: 10,\n      borderRadius: 18,\n      borderColor: INK,\n      /* Round the animated geometry every frame: fractional widths make the\n         object-fit: cover video re-sample each tick, which reads as jitter. */\n      snap: { top: 1, left: 1, width: 1, height: 1, padding: 1, borderRadius: 1 },\n      duration: 0.85,\n      ease: 'power1.inOut'\n    }, 0.05);\n    tl.to(media, { borderRadius: 12, duration: 0.85, ease: 'power1.inOut' }, 0.05);\n    addVideoScrub(tl, v02, 0, 0.9);\n    textIn(tl, 'lin-copy-s2', 1);\n    tl.addLabel('s2', 1);\n\n    /* Section 2 -> 3: floor plan fades in over the video's held last frame */\n    textOut(tl, 'lin-copy-s2', 1.0);\n    tl.to(floorplan, { opacity: 1, duration: 0.4, ease: 'power2.inOut' }, 1.3);\n    textIn(tl, 'lin-copy-s3', 2);\n    tl.addLabel('s3', 2);\n\n    /* Section 3 -> 4: floor plan fades out to the identical photo frame, video 04 scrubs */\n    textOut(tl, 'lin-copy-s3', 2.0);\n    tl.to(floorplan, { opacity: 0, duration: 0.25, ease: 'power2.inOut' }, 2.3);\n    tl.set(v04, { opacity: 1 }, 2.55); // frame-identical hard swap\n    addVideoScrub(tl, v04, 2.55, 0.45);\n    textIn(tl, 'lin-copy-s4', 3);\n    tl.addLabel('s4', 3);\n\n    /* Section 4 -> 5: panel expands to full screen, day turns to night */\n    textOut(tl, 'lin-copy-s4', 3.0);\n    tl.to(panel, {\n      top: 0, left: 0,\n      width: function () { return viewportW(); },\n      height: function () { return viewportH(); },\n      padding: 0,\n      borderRadius: 0,\n      borderColor: INK_0,\n      snap: { top: 1, left: 1, width: 1, height: 1, padding: 1, borderRadius: 1 },\n      duration: 0.65,\n      ease: 'power1.inOut'\n    }, 3.05);\n    tl.to(media, { borderRadius: 0, duration: 0.65, ease: 'power1.inOut' }, 3.05);\n    tl.set(v05, { opacity: 1 }, 3.3); // frame-identical hard swap\n    addVideoScrub(tl, v05, 3.32, 0.62);\n    textIn(tl, 'lin-copy-s5', 4, 0.24);\n    tl.addLabel('s5', 4);\n\n    /* Section 5 -> 6: night matches night, then scrub back into day */\n    textOut(tl, 'lin-copy-s5', 4.0, 0.2);\n    tl.set(v06, { opacity: 1 }, 4.25); // frame-identical hard swap\n    addVideoScrub(tl, v06, 4.28, 0.6);\n    textIn(tl, 'lin-copy-s6', 5, 0.28);\n    tl.addLabel('s6', 5);\n  }\n\n  /* ---------- Reduced motion: normal scroll, simple fades, last frames held ---------- */\n\n  function buildReduced() {\n    gsap.set('.lin-copy-left > *, .lin-copy-center > *', { autoAlpha: 0 });\n\n    var hold = function (video) {\n      if (video.duration) video.currentTime = video.duration - 0.05;\n    };\n    var fade = function (el, opacity) {\n      return gsap.to(el, { opacity: opacity, duration: 0.8, ease: 'power1.inOut', overwrite: 'auto' });\n    };\n    var showCopy = function (id) {\n      return gsap.to(copyEls(id), { autoAlpha: 1, duration: 0.8, ease: 'power1.inOut', overwrite: 'auto' });\n    };\n    var hideCopy = function (id) {\n      return gsap.to(copyEls(id), { autoAlpha: 0, duration: 0.8, ease: 'power1.inOut', overwrite: 'auto' });\n    };\n\n    var contained = function () {\n      var r = panelRect();\n      gsap.to(panel, {\n        top: r.top, left: r.left, width: r.width, height: r.height,\n        padding: 10, borderRadius: 18, borderColor: INK,\n        duration: 0.8, ease: 'power1.inOut', overwrite: 'auto'\n      });\n      gsap.to(media, { borderRadius: 12, duration: 0.8, overwrite: 'auto' });\n    };\n    var fullscreen = function () {\n      gsap.to(panel, {\n        top: 0, left: 0, width: viewportW(), height: viewportH(),\n        padding: 0, borderRadius: 0, borderColor: INK_0,\n        duration: 0.8, ease: 'power1.inOut', overwrite: 'auto'\n      });\n      gsap.to(media, { borderRadius: 0, duration: 0.8, overwrite: 'auto' });\n    };\n\n    var sections = [\n      { // s2\n        enter: function () { contained(); hold(v02); showCopy('lin-copy-s2'); },\n        leaveBack: function () {\n          hideCopy('lin-copy-s2');\n          gsap.to(panel, { top: 0, left: 0, width: viewportW(), height: viewportH(), padding: 0, borderRadius: 0, borderColor: INK_0, duration: 0.8, overwrite: 'auto' });\n          gsap.to(media, { borderRadius: 0, duration: 0.8, overwrite: 'auto' });\n          v02.currentTime = 0.001;\n        }\n      },\n      { // s3\n        enter: function () { hideCopy('lin-copy-s2'); fade(floorplan, 1); showCopy('lin-copy-s3'); },\n        leaveBack: function () { hideCopy('lin-copy-s3'); fade(floorplan, 0); showCopy('lin-copy-s2'); }\n      },\n      { // s4\n        enter: function () { hideCopy('lin-copy-s3'); fade(floorplan, 0); hold(v04); fade(v04, 1); showCopy('lin-copy-s4'); },\n        leaveBack: function () { hideCopy('lin-copy-s4'); fade(v04, 0); fade(floorplan, 1); showCopy('lin-copy-s3'); }\n      },\n      { // s5\n        enter: function () { hideCopy('lin-copy-s4'); fullscreen(); hold(v05); fade(v05, 1); showCopy('lin-copy-s5'); },\n        leaveBack: function () { hideCopy('lin-copy-s5'); fade(v05, 0); contained(); showCopy('lin-copy-s4'); }\n      },\n      { // s6\n        enter: function () { hideCopy('lin-copy-s5'); hold(v06); fade(v06, 1); showCopy('lin-copy-s6'); },\n        leaveBack: function () { hideCopy('lin-copy-s6'); fade(v06, 0); showCopy('lin-copy-s5'); }\n      }\n    ];\n\n    sections.forEach(function (s, i) {\n      ScrollTrigger.create({\n        start: function () { return viewportH() * (i + 0.5); },\n        end: function () { return viewportH() * (i + 1.5); },\n        onEnter: s.enter,\n        onLeaveBack: s.leaveBack\n      });\n    });\n  }\n})();\n"
            },
            "label": "Linden engine (stage + CSS + JS)"
        },
        {
            "id": "lncopy",
            "name": "block",
            "parent": "lnsec",
            "children": [
                "lns2",
                "lns3",
                "lns4",
                "lns5",
                "lns6"
            ],
            "settings": {
                "_cssClasses": "lin-copy"
            },
            "label": "Copy overlays"
        },
        {
            "id": "lns2",
            "name": "block",
            "parent": "lncopy",
            "children": [
                "lns2e",
                "lns2h",
                "lns2b"
            ],
            "settings": {
                "_cssClasses": "lin-copy-left",
                "_cssId": "lin-copy-s2"
            },
            "label": "Copy s2"
        },
        {
            "id": "lns2e",
            "name": "text-basic",
            "parent": "lns2",
            "children": [],
            "settings": {
                "text": "How We Work",
                "tag": "p",
                "_cssClasses": "lin-eyebrow"
            }
        },
        {
            "id": "lns2h",
            "name": "heading",
            "parent": "lns2",
            "children": [],
            "settings": {
                "text": "Every Project Begins From Above",
                "tag": "h2",
                "_cssClasses": "lin-title"
            }
        },
        {
            "id": "lns2b",
            "name": "text-basic",
            "parent": "lns2",
            "children": [],
            "settings": {
                "text": "We step back and see the whole site at once, the land, the light, the way a structure will sit within its surroundings. From this vantage point, the first idea takes shape: rough, open, and full of possibility. Before we decide what a building will be, we look at where it belongs.",
                "tag": "p",
                "_cssClasses": "lin-body"
            }
        },
        {
            "id": "lns3",
            "name": "block",
            "parent": "lncopy",
            "children": [
                "lns3e",
                "lns3h",
                "lns3b"
            ],
            "settings": {
                "_cssClasses": "lin-copy-left",
                "_cssId": "lin-copy-s3"
            },
            "label": "Copy s3"
        },
        {
            "id": "lns3e",
            "name": "text-basic",
            "parent": "lns3",
            "children": [],
            "settings": {
                "text": "How We Work",
                "tag": "p",
                "_cssClasses": "lin-eyebrow"
            }
        },
        {
            "id": "lns3h",
            "name": "heading",
            "parent": "lns3",
            "children": [],
            "settings": {
                "text": "Drawing It Out, Getting Technical",
                "tag": "h2",
                "_cssClasses": "lin-title"
            }
        },
        {
            "id": "lns3b",
            "name": "text-basic",
            "parent": "lns3",
            "children": [],
            "settings": {
                "text": "Once the vision is clear, we translate it into precise lines and measured plans. Ideas meet structure. We work through proportions, materials, and flow, turning imagination into drawings that can actually be built. This is where creativity and engineering start speaking the same language.",
                "tag": "p",
                "_cssClasses": "lin-body"
            }
        },
        {
            "id": "lns4",
            "name": "block",
            "parent": "lncopy",
            "children": [
                "lns4e",
                "lns4h",
                "lns4b"
            ],
            "settings": {
                "_cssClasses": "lin-copy-left",
                "_cssId": "lin-copy-s4"
            },
            "label": "Copy s4"
        },
        {
            "id": "lns4e",
            "name": "text-basic",
            "parent": "lns4",
            "children": [],
            "settings": {
                "text": "How We Work",
                "tag": "p",
                "_cssClasses": "lin-eyebrow"
            }
        },
        {
            "id": "lns4h",
            "name": "heading",
            "parent": "lns4",
            "children": [],
            "settings": {
                "text": "It’s All in the Details",
                "tag": "h2",
                "_cssClasses": "lin-title"
            }
        },
        {
            "id": "lns4b",
            "name": "text-basic",
            "parent": "lns4",
            "children": [],
            "settings": {
                "text": "A building is only as good as its details. We refine every joint, every edge, every transition between materials. The way a handrail meets a wall, the depth of a window reveal, the finish of a surface. These small decisions are what separate a house from a home, a structure from a statement.",
                "tag": "p",
                "_cssClasses": "lin-body"
            }
        },
        {
            "id": "lns5",
            "name": "block",
            "parent": "lncopy",
            "children": [
                "lns5h",
                "lns5e"
            ],
            "settings": {
                "_cssClasses": "lin-copy-center lin-copy-night",
                "_cssId": "lin-copy-s5"
            },
            "label": "Copy s5"
        },
        {
            "id": "lns5h",
            "name": "heading",
            "parent": "lns5",
            "children": [],
            "settings": {
                "text": "Taking It One Step Further",
                "tag": "h2",
                "_cssClasses": "lin-title"
            }
        },
        {
            "id": "lns5e",
            "name": "text-basic",
            "parent": "lns5",
            "children": [],
            "settings": {
                "text": "Good design works in every light.",
                "tag": "p",
                "_cssClasses": "lin-eyebrow"
            }
        },
        {
            "id": "lns6",
            "name": "block",
            "parent": "lncopy",
            "children": [
                "lns6h",
                "lns6s",
                "lns6btn"
            ],
            "settings": {
                "_cssClasses": "lin-copy-center",
                "_cssId": "lin-copy-s6"
            },
            "label": "Copy s6"
        },
        {
            "id": "lns6h",
            "name": "heading",
            "parent": "lns6",
            "children": [],
            "settings": {
                "text": "Let’s Begin From the Ground Up",
                "tag": "h2",
                "_cssClasses": "lin-title"
            }
        },
        {
            "id": "lns6s",
            "name": "text-basic",
            "parent": "lns6",
            "children": [],
            "settings": {
                "text": "If you have a site, an idea, or simply a feeling for the space you want to create, we’d love to hear it.",
                "tag": "p",
                "_cssClasses": "lin-subtext"
            }
        },
        {
            "id": "lns6btn",
            "name": "button",
            "parent": "lns6",
            "children": [],
            "settings": {
                "text": "Start a Project",
                "tag": "button",
                "_cssClasses": "lin-pill"
            }
        },
        {
            "id": "lnnav",
            "name": "block",
            "parent": "lnsec",
            "children": [
                "lnnavl",
                "lnmark",
                "lnnavr"
            ],
            "settings": {
                "_cssClasses": "lin-nav"
            },
            "label": "Nav"
        },
        {
            "id": "lnnavl",
            "name": "block",
            "parent": "lnnav",
            "children": [
                "lnn1",
                "lnn2"
            ],
            "settings": {
                "_cssClasses": "lin-nav-side lin-nav-left"
            }
        },
        {
            "id": "lnn1",
            "name": "text-basic",
            "parent": "lnnavl",
            "children": [],
            "settings": {
                "text": "Studio",
                "tag": "span",
                "_cssClasses": "lin-nav-link"
            }
        },
        {
            "id": "lnn2",
            "name": "text-basic",
            "parent": "lnnavl",
            "children": [],
            "settings": {
                "text": "People",
                "tag": "span",
                "_cssClasses": "lin-nav-link"
            }
        },
        {
            "id": "lnmark",
            "name": "text-basic",
            "parent": "lnnav",
            "children": [],
            "settings": {
                "text": "LINDEN",
                "tag": "div",
                "_cssClasses": "lin-wordmark"
            }
        },
        {
            "id": "lnnavr",
            "name": "block",
            "parent": "lnnav",
            "children": [
                "lnn3",
                "lnn4"
            ],
            "settings": {
                "_cssClasses": "lin-nav-side lin-nav-right"
            }
        },
        {
            "id": "lnn3",
            "name": "text-basic",
            "parent": "lnnavr",
            "children": [],
            "settings": {
                "text": "Press",
                "tag": "span",
                "_cssClasses": "lin-nav-link"
            }
        },
        {
            "id": "lnn4",
            "name": "text-basic",
            "parent": "lnnavr",
            "children": [],
            "settings": {
                "text": "Contact",
                "tag": "span",
                "_cssClasses": "lin-nav-link"
            }
        },
        {
            "id": "lntrack",
            "name": "block",
            "parent": "lnsec",
            "children": [],
            "settings": {
                "_cssClasses": "lin-scroll-track"
            },
            "label": "Scroll track"
        }
    ],
    "media": [
        {
            "attachment_id": 436,
            "file": "drawing-one.jpg",
            "url": "https://gsap.pinul.com/wp-content/uploads/2026/09/drawing-one.jpg",
            "mime": "image/jpeg",
            "bytes": 425838
        },
        {
            "attachment_id": 437,
            "file": "floor-plan.jpg",
            "url": "https://gsap.pinul.com/wp-content/uploads/2026/09/floor-plan.jpg",
            "mime": "image/jpeg",
            "bytes": 338595
        },
        {
            "attachment_id": 438,
            "file": "poster-02-first.jpg",
            "url": "https://gsap.pinul.com/wp-content/uploads/2026/09/poster-02-first.jpg",
            "mime": "image/jpeg",
            "bytes": 400913
        },
        {
            "attachment_id": 439,
            "file": "video-05-day-to-night.webm",
            "url": "https://gsap.pinul.com/wp-content/uploads/2026/09/video-05-day-to-night.webm",
            "mime": "video/webm",
            "bytes": 2773143
        },
        {
            "attachment_id": 440,
            "file": "video-06-night-to-day.webm",
            "url": "https://gsap.pinul.com/wp-content/uploads/2026/09/video-06-night-to-day.webm",
            "mime": "video/webm",
            "bytes": 3562990
        },
        {
            "attachment_id": 441,
            "file": "video-02-top-down.webm",
            "url": "https://gsap.pinul.com/wp-content/uploads/2026/09/video-02-top-down.webm",
            "mime": "video/webm",
            "bytes": 5415140
        },
        {
            "attachment_id": 442,
            "file": "video-04-top-down-to-three-quarter.webm",
            "url": "https://gsap.pinul.com/wp-content/uploads/2026/09/video-04-top-down-to-three-quarter.webm",
            "mime": "video/webm",
            "bytes": 3829710
        },
        {
            "attachment_id": 443,
            "file": "video-02-top-down.mp4",
            "url": "https://gsap.pinul.com/wp-content/uploads/2026/09/video-02-top-down.mp4",
            "mime": "video/mp4",
            "bytes": 8373848
        },
        {
            "attachment_id": 444,
            "file": "video-04-top-down-to-three-quarter.mp4",
            "url": "https://gsap.pinul.com/wp-content/uploads/2026/09/video-04-top-down-to-three-quarter.mp4",
            "mime": "video/mp4",
            "bytes": 6385475
        },
        {
            "attachment_id": 445,
            "file": "video-05-day-to-night.mp4",
            "url": "https://gsap.pinul.com/wp-content/uploads/2026/09/video-05-day-to-night.mp4",
            "mime": "video/mp4",
            "bytes": 5096610
        },
        {
            "attachment_id": 446,
            "file": "video-06-night-to-day.mp4",
            "url": "https://gsap.pinul.com/wp-content/uploads/2026/09/video-06-night-to-day.mp4",
            "mime": "video/mp4",
            "bytes": 5797343
        },
        {
            "attachment_id": 462,
            "file": "thumb-linden.jpg",
            "url": "https://gsap.pinul.com/wp-content/uploads/2026/09/thumb-linden.jpg",
            "mime": "image/jpeg",
            "bytes": 96189
        }
    ],
    "media_note": "The pages build these URLs in JS, so they do not appear literally in the element tree. Re-upload every file below to the target site and point the BASE / src values at the new uploads path."
}