{{- if not (.Param "hideFooter") }}
<footer class="footer reveal-item" role="contentinfo">
    {{- if site.Copyright }}
    <span>{{ site.Copyright | markdownify }}</span>
    {{- else }}
    <span>&copy; {{ now.Year }} <a href="{{ "" | absLangURL }}">{{ site.Title }}</a></span>
    {{- end }}
</footer>
{{- end }}

{{- if (not site.Params.disableScrollToTop) }}
<a href="#top" aria-label="go to top" title="Go to Top (Alt + G)" class="top-link" id="top-link" accesskey="g">
    <svg class="top-link-ring" viewBox="0 0 44 44" aria-hidden="true" focusable="false">
        <circle class="top-link-ring-track" cx="22" cy="22" r="20" />
        <circle class="top-link-ring-progress" cx="22" cy="22" r="20" />
    </svg>
    <svg class="top-link-arrow" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 6" fill="currentColor">
        <path d="M12 6H0l6-6z" />
    </svg>
</a>
{{- end }}

{{- /* Reading Progress Bar (only on single pages) */ -}}
{{- if and (eq .Kind "page") (ne .Layout "archives") (ne .Layout "search") -}}
<div class="reading-progress-bar" id="reading-progress-bar" aria-label="Reading progress"></div>
{{- end -}}

{{- partial "extend_footer.html" . }}

<script>
    let menu = document.getElementById('menu')
    if (menu) {
        menu.scrollLeft = localStorage.getItem("menu-scroll-position");
        menu.onscroll = function () {
            localStorage.setItem("menu-scroll-position", menu.scrollLeft);
        }
    }

    document.querySelectorAll('a[href^="#"]').forEach(anchor => {
        anchor.addEventListener("click", function (e) {
            var id = decodeURIComponent(this.getAttribute("href").substr(1));
            // getElementById tolerates ids with special characters (quotes,
            // colons, CJK) that a `[id='…']` attribute selector would choke
            // on. Guard against missing targets so a stale or "#" link never
            // throws and silently dead-ends the click — it just falls through
            // to the browser's default behaviour instead.
            var target = id ? document.getElementById(id) : null;
            if (!target) return;
            e.preventDefault();
            if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
                target.scrollIntoView({ behavior: "smooth" });
            } else {
                target.scrollIntoView();
            }
            if (id === "top") {
                history.replaceState(null, null, " ");
            } else {
                history.pushState(null, null, `#${id}`);
            }
        });
    });

</script>

{{- if (not site.Params.disableScrollToTop) }}
<script>
    var mybutton = document.getElementById("top-link");
    var ringProgress = mybutton ? mybutton.querySelector('.top-link-ring-progress') : null;
    // Circumference of the r=20 progress ring (2 * PI * 20).
    var RING_CIRC = 125.66;
    function updateTopLink() {
        if (!mybutton) return;
        if (window.innerWidth < 1024) return;
        var scrolled = document.body.scrollTop || document.documentElement.scrollTop;
        if (scrolled > 800) {
            mybutton.style.visibility = "visible";
            mybutton.style.opacity = "1";
        } else {
            mybutton.style.visibility = "hidden";
            mybutton.style.opacity = "0";
        }
        // Drive a CSS spring pop-in (zz-scroll-detail.css). Inline
        // opacity/visibility above is kept for the no-CSS fallback;
        // the class only adds the scale transform on top.
        mybutton.classList.toggle('is-visible', scrolled > 800);
        // Fill the ring in proportion to how far the page has been read.
        if (ringProgress) {
            var trackable = document.documentElement.scrollHeight - document.documentElement.clientHeight;
            var p = trackable > 0 ? Math.min(scrolled / trackable, 1) : 0;
            ringProgress.style.strokeDashoffset = (RING_CIRC * (1 - p)).toFixed(1);
        }
    }
    var topLinkTicking = false;
    window.addEventListener('scroll', function () {
        if (!topLinkTicking) {
            window.requestAnimationFrame(function () {
                updateTopLink();
                topLinkTicking = false;
            });
            topLinkTicking = true;
        }
    }, { passive: true });
    window.matchMedia('(min-width: 1024px)').addEventListener('change', function(e) {
        if (e.matches) updateTopLink();
    });
    updateTopLink();

</script>
{{- end }}

{{- /* Reading Progress Bar Script */ -}}
{{- if and (eq .Kind "page") (ne .Layout "archives") (ne .Layout "search") -}}
<script>
    (function() {
        const progressBar = document.getElementById('reading-progress-bar');
        if (!progressBar) return;

        // Calculate scroll progress
        function updateProgress() {
            const windowHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
            const scrolled = window.scrollY;
            const progress = (scrolled / windowHeight) * 100;
            progressBar.style.width = progress + '%';
            // One-shot "you've reached the end" cue. The class is toggled
            // (not re-added every frame) so the pulse plays once on arrival
            // and replays only if the reader leaves the end and returns.
            // CSS: zz-reading-progress-complete.css (reduced-motion safe).
            progressBar.classList.toggle('is-complete', progress >= 99.5);
        }

        // Throttle scroll events for better performance.
        // Runs on mobile too — the bar is a key scroll cue on phones.
        let ticking = false;
        window.addEventListener('scroll', function() {
            if (!ticking) {
                window.requestAnimationFrame(function() {
                    updateProgress();
                    ticking = false;
                });
                ticking = true;
            }
        }, { passive: true });

        // Keep it accurate when layout height changes (resize / orientation).
        window.addEventListener('resize', function() {
            if (!ticking) {
                window.requestAnimationFrame(function() {
                    updateProgress();
                    ticking = false;
                });
                ticking = true;
            }
        }, { passive: true });

        // Initial update
        updateProgress();
    })();
</script>
{{- end -}}

{{- if (not site.Params.disableThemeToggle) }}
<script>
    (function () {
        var toggle = document.getElementById("theme-toggle");
        if (!toggle) return;

        // The actual theme flip. Kept in one place so the instant path
        // and the animated path stay identical.
        function applyTheme() {
            if (document.body.className.includes("dark")) {
                document.body.classList.remove('dark');
                localStorage.setItem("pref-theme", 'light');
            } else {
                document.body.classList.add('dark');
                localStorage.setItem("pref-theme", 'dark');
            }
        }

        var prefersReduced =
            window.matchMedia &&
            window.matchMedia('(prefers-reduced-motion: reduce)').matches;

        toggle.addEventListener("click", function () {
            // Fallback: no View Transitions API, or reduced motion → flip
            // instantly, exactly as before. Never a half-painted state.
            if (typeof document.startViewTransition !== 'function' || prefersReduced) {
                applyTheme();
                return;
            }

            // Anchor the circular reveal on the toggle button's centre and
            // size it to reach the farthest viewport corner.
            var rect = toggle.getBoundingClientRect();
            var cx = rect.left + rect.width / 2;
            var cy = rect.top + rect.height / 2;
            var vw = window.innerWidth || document.documentElement.clientWidth;
            var vh = window.innerHeight || document.documentElement.clientHeight;
            var r = Math.hypot(Math.max(cx, vw - cx), Math.max(cy, vh - cy));

            var root = document.documentElement;
            root.style.setProperty('--tt-x', cx + 'px');
            root.style.setProperty('--tt-y', cy + 'px');
            root.style.setProperty('--tt-r', r + 'px');
            root.classList.add('theme-switching');

            var vt = document.startViewTransition(applyTheme);
            vt.finished.finally(function () {
                root.classList.remove('theme-switching');
                root.style.removeProperty('--tt-x');
                root.style.removeProperty('--tt-y');
                root.style.removeProperty('--tt-r');
            });
        });
    })();

</script>
{{- end }}

{{- if (and (eq .Kind "page") (ne .Layout "archives") (ne .Layout "search") (.Param "ShowCodeCopyButtons")) }}
<script>
    document.querySelectorAll('pre > code').forEach((codeblock) => {
        const container = codeblock.parentNode.parentNode;

        const copybutton = document.createElement('button');
        copybutton.classList.add('copy-code');
        copybutton.innerHTML = '{{- i18n "code_copy" | default "copy" }}';

        function copyingDone() {
            copybutton.innerHTML = '{{- i18n "code_copied" | default "copied!" }}';
            copybutton.classList.add('is-copied');
            setTimeout(() => {
                copybutton.innerHTML = '{{- i18n "code_copy" | default "copy" }}';
                copybutton.classList.remove('is-copied');
            }, 2000);
        }

        copybutton.addEventListener('click', (cb) => {
            if ('clipboard' in navigator) {
                navigator.clipboard.writeText(codeblock.textContent);
                copyingDone();
                return;
            }

            const range = document.createRange();
            range.selectNodeContents(codeblock);
            const selection = window.getSelection();
            selection.removeAllRanges();
            selection.addRange(range);
            try {
                document.execCommand('copy');
                copyingDone();
            } catch (e) { };
            selection.removeRange(range);
        });

        if (container.classList.contains("highlight")) {
            container.appendChild(copybutton);
        } else if (container.parentNode.firstChild == container) {
            // td containing LineNos
        } else if (codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName == "TABLE") {
            // table containing LineNos and code
            codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.appendChild(copybutton);
        } else {
            // code blocks not having highlight as parent class
            codeblock.parentNode.appendChild(copybutton);
        }
    });
</script>
{{- end }} 