PageSourceSearch

https://creativestrategies.com/assets/js/site.js?v=208da23294

js creativestrategies.com collected 2026-09-24 18:54:07 UTC 8,945 bytes, 186 lines download raw bytes

1(function () {
2    const questions = [
3        {
4            label: 'AI factory economics',
5            question: 'What determines whether an AI factory earns an acceptable return?',
6            title: 'Returns depend on how much capacity is actually used.',
7            answer: 'An AI factory pays off when its computing power is put to work. Electricity, setup time, and the right mix of workloads all shape how much value it creates.',
8            source: '4 reports · 2 maintained models',
9            meta: '4 cited sources',
10            citations: ['AI Factory Economics', 'Compute Utilization Model']
11        },
12        {
13            label: 'Foundry capacity',
14            question: 'How does advanced packaging affect chip production capacity?',
15            title: 'Packaging is becoming the main bottleneck.',
16            answer: 'Making the chips is only part of the challenge. Packaging capacity now affects how quickly those chips can reach customers, which can delay revenue and limit supply.',
17            source: '6 reports · 18 cited passages',
18            meta: '18 cited passages',
19            citations: ['Foundry Economics', 'Packaging Capacity Model']
20        },
21        {
22            label: 'Enterprise AI',
23            question: 'When will AI agents generate lasting software revenue?',
24            title: 'AI agents need to improve how work gets done.',
25            answer: 'Customers will pay more when AI agents save time, complete real tasks, and improve results. The value comes from better work, not simply adding another interface.',
26            source: '5 reports · 1 scorecard',
27            meta: '5 source reports',
28            citations: ['Agentic Workflows', 'Enterprise AI Scorecard']
29        }
30    ];
31
32    document.querySelectorAll('.site-nav a').forEach(function (link) {
33        if (link.pathname === window.location.pathname) link.classList.add('nav-current');
34    });
35
36    const menu = document.querySelector('.menu-button');
37    const nav = document.querySelector('.site-nav');
38    if (menu && nav) {
39        menu.addEventListener('click', function () {
40            const isOpen = nav.classList.toggle('is-open');
41            menu.setAttribute('aria-expanded', String(isOpen));
42        });
43        nav.addEventListener('click', function () {
44            nav.classList.remove('is-open');
45            menu.setAttribute('aria-expanded', 'false');
46        });
47        document.addEventListener('keydown', function (event) {
48            if (event.key === 'Escape' && nav.classList.contains('is-open')) {
49                nav.classList.remove('is-open');
50                menu.setAttribute('aria-expanded', 'false');
51                menu.focus();
52            }
53        });
54    }
55
56    const tabs = Array.from(document.querySelectorAll('.prompt-tabs button'));
57    const question = document.querySelector('.portal-answer h4');
58    const resultTitle = document.querySelector('.portal-response h3');
59    const answer = document.querySelector('.portal-answer p');
60    const source = document.querySelector('[data-answer-source]');
61    const resultMeta = document.querySelector('.portal-response-meta > span:last-child');
62    const citations = Array.from(document.querySelectorAll('.portal-citation'));
63
64    function selectQuestion(index) {
65        if (!question || !resultTitle || !answer || !source || !resultMeta || !questions[index]) return;
66        tabs.forEach(function (tab, tabIndex) {
67            const selected = tabIndex === index;
68            tab.classList.toggle('active', selected);
69            tab.setAttribute('aria-selected', String(selected));
70        });
71        question.textContent = questions[index].question;
72        resultTitle.textContent = questions[index].title;
73        answer.textContent = questions[index].answer;
74        source.textContent = questions[index].source;
75        resultMeta.textContent = questions[index].meta;
76        citations.forEach(function (citation, citationIndex) {
77            citation.innerHTML = '<b>[' + (citationIndex + 1) + ']</b> ' + questions[index].citations[citationIndex];
78        });
79    }
80
81    tabs.forEach(function (tab, index) {
82        tab.addEventListener('click', function () { selectQuestion(index); });
83    });
84
85    document.querySelectorAll('[data-newsletter-role]').forEach(function (role) {
86        const form = role.closest('[data-members-form]');
87        const roleLabel = form && form.querySelector('[data-newsletter-role-label]');
88        if (!form || !roleLabel) return;
89
90        function updateRoleLabel() {
91            roleLabel.value = role.value ? 'Role: ' + role.value : '';
92            roleLabel.disabled = !role.value;
93        }
94
95        role.addEventListener('change', updateRoleLabel);
96        form.addEventListener('submit', updateRoleLabel, true);
97        updateRoleLabel();
98    });
99
100    document.querySelectorAll('[data-contact-form]').forEach(function (form) {
101        const button = form.querySelector('button[type="submit"]');
102        const success = form.querySelector('.form-success');
103        const error = form.querySelector('.form-error');
104        const inquiryCategory = form.querySelector('[name="inquiry-category"]');
105        const requestedInterest = new URLSearchParams(window.location.search).get('interest');
106
107        if (
108            inquiryCategory &&
109            requestedInterest &&
110            Array.from(inquiryCategory.options).some(function (option) {
111                return option.value === requestedInterest;
112            })
113        ) {
114            inquiryCategory.value = requestedInterest;
115        }
116
117        form.addEventListener('submit', async function (event) {
118            event.preventDefault();
119            const endpoint = form.getAttribute('data-endpoint');
120            if (!endpoint || !button || !success || !error) return;
121
122            const fields = new FormData(form);
123            success.hidden = true;
124            error.hidden = true;
125            form.classList.add('loading');
126            form.setAttribute('aria-busy', 'true');
127            button.disabled = true;
128
129            try {
130                const response = await fetch(endpoint, {
131                    method: 'POST',
132                    headers: {'Content-Type': 'application/json'},
133                    body: JSON.stringify({
134                        firstName: fields.get('first-name'),
135                        lastName: fields.get('last-name'),
136                        email: fields.get('email'),
137                        company: fields.get('company') || '',
138                        inquiryCategory: fields.get('inquiry-category') || '',
139                        message: fields.get('message'),
140                        website: fields.get('website'),
141                        turnstileToken: fields.get('cf-turnstile-response') || ''
142                    })
143                });
144                const result = await response.json().catch(function () { return {}; });
145                if (!response.ok) {
146                    const retryAfterSeconds = Number.parseInt(response.headers.get('Retry-After'), 10);
147                    if (response.status === 429 && retryAfterSeconds > 0) {
148                        const useMinutes = retryAfterSeconds >= 60;
149                        const retryDelay = useMinutes
150                            ? Math.ceil(retryAfterSeconds / 60)
151                            : retryAfterSeconds;
152                        const retryUnit = useMinutes ? 'minute' : 'second';
153                        throw new Error(
154                            'You have sent several messages. Please try again in ' +
155                            retryDelay + ' ' + retryUnit + (retryDelay === 1 ? '' : 's') + '.'
156                        );
157                    }
158                    throw new Error(result.error || 'We could not send your message. Please try again.');
159                }
160
161                form.reset();
162                success.hidden = false;
163            } catch (submissionError) {
164                error.textContent = submissionError.message || 'We could not send your message. Please try again.';
165                error.hidden = false;
166            } finally {
167                form.classList.remove('loading');
168                form.removeAttribute('aria-busy');
169                button.disabled = false;
170                if (window.turnstile) window.turnstile.reset();
171            }
172        });
173    });
174
175    const filters = Array.from(document.querySelectorAll('[data-filter]'));
176    const articleCards = Array.from(document.querySelectorAll('[data-category]'));
177    filters.forEach(function (filter) {
178        filter.addEventListener('click', function () {
179            const value = filter.getAttribute('data-filter');
180            filters.forEach(function (item) { item.classList.toggle('active', item === filter); });
181            articleCards.forEach(function (card) {
182                card.hidden = value !== 'all' && card.getAttribute('data-category') !== value;
183            });
184        });
185    });
186}());

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.