PageSourceSearch

https://creaconnect.world/src/crea-ecosystem.js

js creaconnect.world collected 2026-09-24 10:10:21 UTC 23,378 bytes, 347 lines download raw bytes

1/* ============================================================
2 * CREA ECOSYSTEM — centre de visibilité des briques vivantes.
3 * REND : dessiner
4 *
5 * Lecture seule : montre les modules frontend réellement chargés, les systèmes
6 * backend, leurs verrous et les règles de déploiement. Aucun secret ni bouton
7 * d'activation sensible n'est exposé.
8 *
9 * Chargé après CREA_API. Expose window.CREA_ECOSYSTEM.
10 * ============================================================ */
11;(function () {
12  'use strict'
13  if (window.CREA_ECOSYSTEM) return
14
15  var MODULES = [
16    ['CREA_IDB', 'Mémoire locale IndexedDB'],
17    ['CREA_IDENTITY', 'Identité canonique'],
18    ['CREA_SOCLE', 'Socle universel'],
19    ['CREA_NERVE', 'Système nerveux'],
20    ['CREA_ADAPT', 'Adaptation multi-support'],
21    ['CREA_ECOSYSTEM', 'Centre Écosystème'],
22    ['CREA_API', 'Client API partagé'],
23    ['CREA_LIVING', 'Coordinateur visuel'],
24    ['CREA_TRANSFORM', 'Transformations'],
25    ['CREA_PROPOSE', 'Propositions contextuelles'],
26    ['CREA_SMARTBAR', 'Barre intelligente'],
27    ['CREA_SOCIETY', 'Société IA, DLM et agents'],
28    ['CREA_CONTEXT', 'Contexte écosystème'],
29    ['CREA_DOC', 'Documents vivants'],
30    ['CREA_OMNIS', 'Relations et Command Center'],
31    ['CREA_PREVIEW_GUARD', 'Protection des aperçus'],
32    ['CREA_JOURNAL', 'Journal vivant'],
33    ['CREA_VIEWS', 'Vues projet et agent'],
34    ['CREA_MENTION', 'Mentions de ressources'],
35    ['CREA_GUIDE', 'Guide vivant'],
36    ['CREA_TERMINAL', 'Terminal Créa'],
37    ['CREA_BAR', 'Réglages Affiner'],
38    ['CREA_RESILIENCE', 'Résilience réseau'],
39    ['CREA_VOICE', 'Voix et dictée'],
40    ['CREA_CONNECT', 'Connecteurs'],
41    ['CREA_ACCESS', 'Niveaux d\'accès'],
42    ['CREA_CONSENT', 'Consentements'],
43    ['CREA_CONSTITUTION', 'Constitution'],
44    ['CREA_KNOWLEDGE', 'Bibliothèques'],
45    ['CREA_GUARDIAN', 'Garde-fous'],
46    ['CREA_MEDIA', 'Studio média'],
47    ['CREA_FINITION', 'Agent finition'],
48    ['CREA_EMERGENCE', 'Émergence'],
49    ['CREA_ROUTER', 'Routeur cognitif'],
50    ['CREA_TIME', 'Studio temps'],
51    ['CREA_RAG', 'RAG source'],
52    ['CREA_WORLD', 'Monde réel'],
53    ['CREA_SOURCES', 'Sources par domaine'],
54    ['CREA_PREMIUM', 'Finition visuelle'],
55    ['CREA_SELF', 'Connaissance de soi'],
56  ]
57
58  var latest = null
59
60  function esc(value) {
61    return String(value == null ? '' : value).replace(/[&<>"']/g, function (char) {
62      return ({ '&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;', "'":'&#39;' })[char]
63    })
64  }
65
66  function localSnapshot() {
67    var modules = MODULES.map(function (item) {
68      return { id:item[0], name:item[1], active:Boolean(window[item[0]]) }
69    })
70    var adapt = null
71    try { adapt = window.CREA_ADAPT && window.CREA_ADAPT.current && window.CREA_ADAPT.current() } catch (e) {}
72    return {
73      modules:modules,
74      active:modules.filter(function (item) { return item.active }).length,
75      expected:modules.length,
76      profile:adapt && adapt.profile || String(window.__CREA_APP_PROFILE || 'inconnu'),
77      platform:adapt && adapt.platform || 'inconnu',
78      viewport:adapt ? adapt.width + 'x' + adapt.height : window.innerWidth + 'x' + window.innerHeight,
79    }
80  }
81
82  function activeSurface() {
83    var profile = String(window.__CREA_APP_PROFILE || '').toLowerCase()
84    if (profile.indexOf('console') >= 0) return 'console'
85    if (profile.indexOf('public') >= 0 || profile.indexOf('client') >= 0) return 'public'
86    try {
87      var adapt = window.CREA_ADAPT && window.CREA_ADAPT.current && window.CREA_ADAPT.current()
88      var surface = String(adapt && (adapt.surface || adapt.profile) || '').toLowerCase()
89      if (surface.indexOf('console') >= 0) return 'console'
90      if (surface.indexOf('public') >= 0 || surface.indexOf('client') >= 0) return 'public'
91    } catch (e) {}
92    return location.pathname.indexOf('console') >= 0 || location.pathname.indexOf('admin') >= 0 ? 'console' : 'public'
93  }
94
95  function closeNearby() {
96    [
97      'crea-guide', 'crea-terminal', 'crea-cc', 'crea-self', 'crea-society',
98      'crea-connect', 'crea-access', 'crea-consent', 'crea-knowledge',
99      'crea-constitution', 'crea-guardian', 'crea-media', 'crea-finition',
100      'crea-emergence', 'crea-router', 'crea-time', 'crea-rag', 'crea-sources'
101    ].forEach(function (id) {
102      var node = document.getElementById(id)
103      if (node) node.remove()
104    })
105  }
106
107  function statusLabel(status) {
108    return ({
109      active:'Actif',
110      wired:'Branché',
111      gated:'Protégé',
112      preserved:'Conservé',
113      superseded:'Remplacé',
114    })[status] || String(status || 'Inconnu')
115  }
116
117  function statusClass(status) {
118    if (status === 'active') return 'on'
119    if (status === 'wired') return 'wired'
120    if (status === 'gated') return 'gate'
121    return 'quiet'
122  }
123
124  async function load() {
125    var backend = null
126    var files = null
127    try {
128      backend = window.CREA_API && window.CREA_API.ecosystemStatus
129        ? await window.CREA_API.ecosystemStatus()
130        : await fetch('/api/ecosystem/status', { cache:'no-store', credentials:'same-origin' }).then(function (response) {
131            if (!response.ok) throw new Error('http-' + response.status)
132            return response.json()
133          })
134    } catch (error) {
135      backend = { ok:false, error:String(error && error.message || error), systems:[], totals:{} }
136    }
137    try {
138      var surface = activeSurface()
139      files = window.CREA_API && window.CREA_API.ecosystemFiles
140        ? await window.CREA_API.ecosystemFiles({ surface:surface, maxFiles:12000, maxDepth:10 })
141        : await fetch('/api/ecosystem/files?surface=' + encodeURIComponent(surface) + '&maxFiles=12000&maxDepth=10', { cache:'no-store', credentials:'same-origin' }).then(function (response) {
142            if (!response.ok) throw new Error('http-' + response.status)
143            return response.json()
144          })
145    } catch (error) {
146      files = { ok:false, error:String(error && error.message || error), files:[], directories:[], totals:{ files:0, directories:0, omitted:0 } }
147    }
148    latest = { local:localSnapshot(), backend:backend, files:files, at:Date.now() }
149    return latest
150  }
151
152  function rulesHtml(data) {
153    var rules = data.backend && data.backend.rules || {}
154    if (!data.backend || data.backend.ok !== true) {
155      return '<div class="ce-rules"><span class="unknown">État serveur non vérifié</span><span>Règles locales inchangées</span><span>Actions sensibles : validation humaine</span></div>'
156    }
157    var open = rules.openAccess === true
158    var unlimited = rules.usageQuotasEnabled === false
159    return '<div class="ce-rules">' +
160      '<span class="' + (open ? 'ok' : 'warn') + '">Accès ' + (open ? 'ouvert' : 'restreint') + '</span>' +
161      '<span class="' + (unlimited ? 'ok' : 'warn') + '">Quotas ' + (unlimited ? 'illimités' : 'actifs') + '</span>' +
162      '<span>Actions sensibles : validation humaine</span>' +
163      '</div>'
164  }
165
166  function backendRows(data) {
167    var systems = data.backend && data.backend.systems || []
168    if (!systems.length) return '<div class="ce-empty">
168Backend indisponible. Les modules locaux restent utilisables.</div>'
169    return systems.map(function (system) {
170      var missing = (system.files || []).filter(function (file) { return !file.present }).map(function (file) { return file.path })
171      var detail = missing.length
172        ? 'Manquant: ' + missing.join(', ')
173        : (system.gate ? 'Verrou: ' + system.gate : system.domain)
174      return '<div class="ce-row">' +
175        '<span class="ce-dot ' + statusClass(system.status) + '"></span>' +
176        '<div class="ce-main"><b>' + esc(system.name) + '</b><small>' + esc(detail) + '</small></div>' +
177        '<span class="ce-badge ' + statusClass(system.status) + '">' + esc(statusLabel(system.status)) + '</span>' +
178        '</div>'
179    }).join('')
180  }
181
182  function localRows(data) {
183    return data.local.modules.map(function (module) {
184      return '<div class="ce-module"><span class="ce-dot ' + (module.active ? 'on' : 'gate') + '"></span><span>' +
185        esc(module.name) + '</span><small>' + (module.active ? 'actif' : 'non chargé') + '</small></div>'
186    }).join('')
187  }
188
189  function statPills(map) {
190    return Object.keys(map || {}).sort().map(function (key) {
191      return '<span><b>' + esc(map[key]) + '</b> ' + esc(key) + '</span>'
192    }).join('')
193  }
194
195  function directoryRows(files) {
196    var dirs = files && files.directories || []
197    if (!dirs.length) return '<div class="ce-empty">Aucun dossier visible pour cette surface.</div>'
198    return dirs.map(function (dir) {
199      return '<div class="ce-dir"><span>' + esc(dir.path) + '</span><b>' + esc(dir.count) + '</b></div>'
200    }).join('')
201  }
202
203  function fileRows(files) {
204    var list = files && files.files || []
205    if (!list.length) return '<div class="ce-empty">Aucun fichier visible pour cette surface.</div>'
206    return list.map(function (file) {
207      return '<div class="ce-file">' +
208        '<span class="ce-badge quiet">' + esc(file.surface) + '</span>' +
209        '<div><b>' + esc(file.path) + '</b><small>' + esc(file.area + ' - ' + file.kind + ' - ' + Math.ceil((file.size || 0) / 1024) + ' Ko') + '</small></div>' +
210      '</div>'
211    }).join('')
212  }
213
214  function filesHtml(data) {
215    var files = data.files || {}
216    var totals = files.totals || {}
217    var omitted = files.omitted || {}
218    if (files.ok !== true) {
219      return '<section><h3>Inventaire fichiers</h3><div class="ce-empty">Inventaire indisponible : ' + esc(files.error || 'erreur') + '</div></section>'
220    }
221    return '<section><h3>Inventaire fichiers ' + esc(files.surface || activeSurface()) + '</h3>' +
222      '<div class="ce-inventory-head">' +
223        '<div><b>' + esc(totals.files || 0) + '</b><span>fichiers visibles</span></div>' +
224        '<div><b>' + esc(totals.directories || 0) + '</b><span>dossiers</span></div>' +
225        '<div><b>' + esc(totals.omitted || 0) + '</b><span>protégés/ignorés</span></div>' +
226      '</div>' +
227      '<div class="ce-pills">' + statPills(files.bySurface) + statPills(files.byArea) + '</div>' +
228      '<div class="ce-inventory-grid">' +
229        '<div><h4>Dossiers</h4><div class="ce-dir-list">' + directoryRows(files) + '</div></div>' +
230        '<div><h4>Fichiers</h4><div class="ce-file-list">' + fileRows(files) + '</div></div>' +
231      '</div>' +
232      '<p class="ce-foot">Inventaire lecture seule : chemins relatifs et métadonnées. Secrets, tokens, .env, caches lourds et node_modules restent cachés. Omission : secrets ' + esc(omitted.secret || 0) + ', dossiers ' + esc(omitted.dirs || 0) + ', lourds ' + esc(omitted.heavy || 0) + '.</p>' +
233      '</section>'
234  }
235
236  function draw(data) {
237    var root = document.getElementById('crea-ecosystem')
238    if (!root) return
239    var totals = data.backend && data.backend.totals || {}
240    root.querySelector('.ce-body').innerHTML =
241      rulesHtml(data) +
242      '<div class="ce-summary">' +
243        '<div><b>' + data.local.active + '/' + data.local.expected + '</b><span>couches navigateur</span></div>' +
244        '<div><b>' + (totals.ready || 0) + '/' + (totals.systems || 0) + '</b><span>systèmes opérationnels</span></div>' +
245        '<div><b>' + esc(data.local.profile) + '</b><span>
245' + esc(data.local.platform + ' - ' + data.local.viewport) + '</span></div>' +
246      '</div>' +
247      '<section><h3>Backend et écosystème</h3><div class="ce-list">' + backendRows(data) + '</div></section>' +
248      filesHtml(data) +
249      '<section><h3>Couches chargées sur cet appareil</h3><div class="ce-modules">' + localRows(data) + '</div></section>' +
250      '<p class="ce-foot">Les éléments protégés demandent un secret, un consentement ou un environnement adapté. Les prototypes remplacés restent conservés sans être exécutés en double.</p>'
251  }
252
253  async function refresh() {
254    var root = document.getElementById('crea-ecosystem')
255    if (root) root.classList.add('loading')
256    var data = await load()
257    if (root) {
258      root.classList.remove('loading')
259      draw(data)
260    }
261    return data
262  }
263
264  function open() {
265    var existing = document.getElementById('crea-ecosystem')
266    if (existing) { existing.remove(); return }
267    closeNearby()
268    var overlay = document.createElement('div')
269    overlay.id = 'crea-ecosystem'
270    overlay.setAttribute('role', 'dialog')
271    overlay.setAttribute('aria-modal', 'true')
272    overlay.setAttribute('aria-label', 'Centre Écosystème')
273    overlay.innerHTML =
274      '<div class="ce-box">' +
275        '<header><div><strong>Centre Écosystème</strong><span>État réel de CREA sur cet appareil et son backend</span></div>' +
276        '<button type="button" data-refresh title="Actualiser" aria-label="Actualiser">↻</button>' +
277        '<button type="button" data-close title="Fermer" aria-label="Fermer">×</button></header>' +
278        '<div class="ce-body"><div class="ce-loading">Lecture de l\'écosystème...</div></div>' +
279      '</div>'
280    document.body.appendChild(overlay)
281    overlay.addEventListener('mousedown', function (event) { if (event.target === overlay) overlay.remove() })
282    overlay.addEventListener('click', function (event) {
283      if (event.target.closest('[data-close]')) overlay.remove()
284      if (event.target.closest('[data-refresh]')) refresh()
285    })
286    document.addEventListener('keydown', function onEscape(event) {
287      if (event.key === 'Escape') {
288        overlay.remove()
289        document.removeEventListener('keydown', onEscape)
290      }
291    })
292    refresh()
293  }
294
295  function refreshLauncher() {
296    // Bouton flottant « Eco » supprimé (épure de l'interface).
297    // Le centre reste accessible via window.CREA_ECOSYSTEM.open().
298    var button = document.getElementById('crea-ecosystem-launch')
299    if (button) button.remove()
300  }
301
302  function css() {
303    if (document.getElementById('crea-ecosystem-css')) return
304    var style = document.createElement('style')
305    style.id = 'crea-ecosystem-css'
306    style.textContent =
307      '#crea-ecosystem{position:fixed;inset:0;z-index:90040;background:rgba(0,0,0,.56);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;padding:max(14px,env(safe-area-inset-top)) max(14px,env(safe-area-inset-right)) max(14px,env(safe-area-inset-bottom)) max(14px,env(safe-area-inset-left))}' +
308      '#crea-ecosystem .ce-box{width:min(920px,100%);max-height:min(88vh,var(--crea-vh,88vh));display:flex;flex-direction:column;overflow:hidden;background:var(--bg-secondary,#151719);border:1px solid var(--border,#34383d);border-radius:8px;box-shadow:0 24px 70px rgba(0,0,0,.55)}' +
309      '#crea-ecosystem header{display:flex;align-items:center;gap:8px;padding:13px 15px;border-bottom:1px solid var(--border,#34383d)}' +
310      '#crea-ecosystem header>div{flex:1;min-width:0;display:flex;flex-direction:column}#crea-ecosystem header strong{color:var(--t-primary,#f3f4f6);font:700 15px Inter,system-ui,sans-serif}#crea-ecosystem header span{color:var(--t-faint,#9ca3af);font:500 11.5px Inter,system-ui,sans-serif;white-space:normal}' +
311      '#crea-ecosystem header button{width:34px;height:34px;flex:0 0 34px;border:1px solid var(--border,#34383d);border-radius:6px;background:var(--bg-tertiary,#202326);color:var(--t-secondary,#d1d5db);font:600 18px Inter,system-ui,sans-serif;cursor:pointer}' +
312      '#crea-ecosystem.loading [data-refresh]{animation:ce-spin .8s linear infinite}#crea-ecosystem .ce-body{overflow:auto;padding:14px 15px 16px}' +
313      '#crea-ecosystem .ce-rules{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:12px}#crea-ecosystem .ce-rules span{border:1px solid var(--border,#34383d);border-radius:999px;padding:5px 9px;color:var(--t-secondary,#d1d5db);font:600 11px Inter,system-ui,sans-serif}#crea-ecosystem .ce-rules .ok{border-color:#237a5a;color:#69d7ad;background:rgba(35,122,90,.12)}#crea-ecosystem .ce-rules .warn{border-color:#9a6b22;color:#f2c66d;background:rgba(154,107,34,.12)}#crea-ecosystem .ce-rules .unknown{border-color:#64748b;color:#94a3b8;background:rgba(100,116,139,.12)}' +
314      '#crea-ecosystem .ce-summary{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));border-top:1px solid var(--border,#34383d);border-bottom:1px solid var(--border,#34383d);margin-bottom:15px}#crea-ecosystem .ce-summary>div{min-width:0;padding:11px 12px;border-right:1px solid var(--border,#34383d);display:flex;flex-direction:column}#crea-ecosystem .ce-summary>div:last-child{border-right:0}#crea-ecosystem .ce-summary b{color:var(--t-primary,#f3f4f6);font:700 14px Inter,system-ui,sans-serif;overflow-wrap:anywhere}#crea-ecosystem .ce-summary span{color:var(--t-faint,#9ca3af);font:500 10.5px Inter,system-ui,sans-serif;margin-top:2px}' +
315      '#crea-ecosystem section+section{margin-top:17px}#crea-ecosystem h3{margin:0 0 7px;color:var(--t-secondary,#d1d5db);font:700 11px Inter,system-ui,sans-serif;text-transform:uppercase;letter-spacing:.05em}' +
316      '#crea-ecosystem .ce-list{border-top:1px solid var(--border,#34383d)}#crea-ecosystem .ce-row{display:flex;align-items:center;gap:10px;min-height:48px;padding:7px 4px;border-bottom:1px solid var(--border,#34383d)}#crea-ecosystem .ce-main{flex:1;min-width:0;display:flex;flex-direction:column}#crea-ecosystem .ce-main b{color:var(--t-primary,#f3f4f6);font:600 12.5px Inter,system-ui,sans-serif}#crea-ecosystem .ce-main small{color:var(--t-faint,#9ca3af);font:500 10.5px/1.4 Inter,system-ui,sans-serif;overflow-wrap:anywhere}' +
317      '#crea-ecosystem .ce-dot{width:8px;height:8px;border-radius:50%;flex:0 0 8px;background:#737982}#crea-ecosystem .ce-dot.on{background:#35b982}#crea-ecosystem .ce-dot.wired{background:#4ea1d3}#crea-ecosystem .ce-dot.gate{background:#d39a40}' +
318      '#crea-ecosystem .ce-badge{flex:0 0 auto;border:1px solid var(--border,#34383d);border-radius:999px;padding:4px 8px;color:var(--t-faint,#9ca3af);font:700 9.5px Inter,system-ui,sans-serif;text-transform:uppercase}#crea-ecosystem .ce-badge.on{color:#69d7ad;border-color:#237a5a}#crea-ecosystem .ce-badge.wired{color:#83c7ef;border-color:#326b8d}#crea-ecosystem .ce-badge.gate{color:#f2c66d;border-color:#9a6b22}' +
319      '#crea-ecosystem .ce-inventory-head{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));border:1px solid var(--border,#34383d);border-radius:8px;overflow:hidden;margin-bottom:9px}#crea-ecosystem .ce-inventory-head>div{min-width:0;padding:9px 10px;border-right:1px solid var(--border,#34383d);display:flex;flex-direction:column}#crea-ecosystem .ce-inventory-head>div:last-child{border-right:0}#crea-ecosystem .ce-inventory-head b{color:var(--t-primary,#f3f4f6);font:700 13px Inter,system-ui,sans-serif}#crea-ecosystem .ce-inventory-head span{color:var(--t-faint,#9ca3af);font:500 10px Inter,system-ui,sans-serif}' +
320      '#crea-ecosystem .ce-pills{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 10px}#crea-ecosystem .ce-pills span{border:1px solid var(--border,#34383d);border-radius:999px;padding:4px 8px;color:var(--t-faint,#9ca3af);font:600 10px Inter,system-ui,sans-serif}#crea-ecosystem .ce-pills b{color:var(--t-secondary,#d1d5db);font-weight:800}' +
321      '#crea-ecosystem .ce-inventory-grid{display:grid;grid-template-columns:minmax(190px,.65fr) minmax(0,1.35fr);gap:12px}#crea-ecosystem h4{margin:0 0 6px;color:var(--t-faint,#9ca3af);font:700 10px Inter,system-ui,sans-serif;text-transform:uppercase;letter-spacing:.04em}' +
322      '#crea-ecosystem .ce-dir-list,#crea-ecosystem .ce-file-list{border:1px solid var(--border,#34383d);border-radius:8px;overflow:auto;max-height:330px;background:rgba(0,0,0,.08)}#crea-ecosystem .ce-dir{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;padding:6px 8px;border-bottom:1px solid var(--border,#34383d)}#crea-ecosystem .ce-dir span{min-width:0;color:var(--t-secondary,#d1d5db);font:500 10.5px Inter,system-ui,sans-serif;overflow-wrap:anywhere}#crea-ecosystem .ce-dir b{color:var(--t-faint,#9ca3af);font:700 10px Inter,system-ui,sans-serif}' +
323      '#crea-ecosystem .ce-file{display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px;align-items:start;padding:7px 8px;border-bottom:1px solid var(--border,#34383d)}#crea-ecosystem .ce-file>div{min-width:0;display:flex;flex-direction:column}#crea-ecosystem .ce-file b{color:var(--t-primary,#f3f4f6);font:600 10.8px Inter,system-ui,sans-serif;overflow-wrap:anywhere}#crea-ecosystem .ce-file small{color:var(--t-faint,#9ca3af);font:500 9.5px Inter,system-ui,sans-serif;margin-top:2px}' +
324      '#crea-ecosystem .ce-modules{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));column-gap:18px}#crea-ecosystem .ce-module{min-width:0;display:grid;grid-template-columns:8px minmax(0,1fr) auto;align-items:center;gap:9px;padding:7px 2px;border-bottom:1px solid var(--border,#34383d)}#crea-ecosystem .ce-module span:nth-child(2){color:var(--t-secondary,#d1d5db);font:500 11.5px Inter,system-ui,sans-serif;overflow-wrap:anywhere}#crea-ecosystem .ce-module small{color:var(--t-faint,#9ca3af);font:600 9.5px Inter,system-ui,sans-serif}' +
325      '#crea-ecosystem .ce-foot,#crea-ecosystem .ce-empty,#crea-ecosystem .ce-loading{color:var(--t-faint,#9ca3af);font:500 11px/1.5 Inter,system-ui,sans-serif}#crea-ecosystem .ce-foot{margin:14px 0 0}#crea-ecosystem .ce-empty,#crea-ecosystem .ce-loading{padding:18px 3px}' +
326      '#crea-ecosystem-launch{position:fixed;right:14px;bottom:calc(env(safe-area-inset-bottom,0px) + 142px);z-index:86010;height:38px;min-width:38px;border-radius:19px;border:1px solid var(--border,#333);background:var(--bg-secondary,#161616);color:var(--t-primary,#eee);display:flex;align-items:center;justify-content:center;gap:5px;padding:0 10px;font:700 11px Inter,system-ui,sans-serif;box-shadow:0 6px 18px rgba(0,0,0,.25);opacity:.72;cursor:pointer;transition:opacity .15s,transform .15s}' +
327      '#crea-ecosystem-launch:hover{opacity:1;transform:scale(1.05)}#crea-ecosystem-launch span{font-size:16px;line-height:1}#crea-ecosystem-launch b{font:700 10px Inter,system-ui,sans-serif;letter-spacing:0;text-transform:uppercase}' +
328      '@media(max-width:680px){#crea-ecosystem{align-items:stretch;padding:0}#crea-ecosystem .ce-box{width:100%;max-height:var(--crea-vh,100dvh);height:var(--crea-vh,100dvh);border:0;border-radius:0}#crea-ecosystem .ce-summary,#crea-ecosystem .ce-inventory-head{grid-template-columns:1fr}#crea-ecosystem .ce-summary>div,#crea-ecosystem .ce-inventory-head>div{border-right:0;border-bottom:1px solid var(--border,#34383d)}#crea-ecosystem .ce-summary>div:last-child,#crea-ecosystem .ce-inventory-head>div:last-child{border-bottom:0}#crea-ecosystem .ce-inventory-grid{grid-template-columns:1fr}#crea-ecosystem .ce-dir-list,#crea-ecosystem .ce-file-list{max-height:260px}#crea-ecosystem .ce-modules{grid-template-columns:1fr}#crea-ecosystem .ce-badge{font-size:8.5px}#crea-ecosystem-launch{right:12px;bottom:calc(env(safe-area-inset-bottom,0px) + 192px);height:34px;min-width:34px;border-radius:17px;padding:0 8px}#crea-ecosystem-launch b{display:none}}' +
329      '@keyframes ce-spin{to{transform:rotate(360deg)}}'
330    document.head.appendChild(style)
331  }
332
333  function start() {
334    css()
335    refreshLauncher()
336  }
337
338  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start)
339  else start()
340
341  window.CREA_ECOSYSTEM = {
342    open:open,
343    refresh:refresh,
344    refreshLauncher:refreshLauncher,
345    snapshot:function () { return latest || { local:localSnapshot(), backend:null } },
346  }
347})()

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.