/** Shared, dependency-free customer experience primitives for Nexus One AI. */ (function (global) { 'use strict'; var STATES = ['loading', 'empty', 'ready', 'degraded', 'failed', 'restricted', 'unavailable', 'stale']; var SEVERITIES = ['info', 'warning', 'critical']; function canonicalState(value) { value = String(value || '').toLowerCase().replace(/[_ ]+/g, '-'); var aliases = { ok: 'ready', healthy: 'ready', limited: 'degraded', warning: 'degraded', error: 'failed', critical: 'failed', not_ready: 'failed' }; value = aliases[value] || value; return STATES.indexOf(value) >= 0 ? value : 'unavailable'; } function announce(message, priority) { var id = priority === 'assertive' ? 'cezen-live-assertive' : 'cezen-live-polite'; var region = document.getElementById(id); if (!region) { region = document.createElement('div'); region.id = id; region.className = 'sr-only'; region.setAttribute('aria-live', priority === 'assertive' ? 'assertive' : 'polite'); region.setAttribute('aria-atomic', 'true'); document.body.appendChild(region); } region.textContent = ''; global.setTimeout(function () { region.textContent = String(message || ''); }, 20); } function renderState(element, payload) { if (!element) return; payload = payload || {}; var state = canonicalState(payload.state || payload.status); var severity = SEVERITIES.indexOf(payload.severity) >= 0 ? payload.severity : (state === 'failed' ? 'critical' : state === 'degraded' || state === 'stale' ? 'warning' : 'info'); element.classList.remove.apply(element.classList, STATES.map(function (item) { return 'cx-state-' + item; })); element.classList.add('cx-state', 'cx-state-' + state); element.setAttribute('data-state', state); element.setAttribute('data-severity', severity); element.setAttribute('role', severity === 'critical' ? 'alert' : 'status'); element.textContent = payload.summary || state.replace(/-/g, ' '); } function formatFreshness(observedAt, now) { if (!observedAt) return 'Freshness unknown'; var observed = new Date(observedAt).getTime(); var current = now ? new Date(now).getTime() : Date.now(); if (!isFinite(observed)) return 'Freshness unknown'; var seconds = Math.max(0, Math.round((current - observed) / 1000)); if (seconds < 60) return 'Observed ' + seconds + ' seconds ago'; if (seconds < 3600) return 'Observed ' + Math.floor(seconds / 60) + ' minutes ago'; return 'Observed ' + Math.floor(seconds / 3600) + ' hours ago'; } function focusFirstError(container) { var target = (container || document).querySelector('[aria-invalid="true"], .field-error, .cx-error'); if (!target) return false; if (!target.hasAttribute('tabindex')) target.setAttribute('tabindex', '-1'); target.focus(); return true; } global.CezenExperience = Object.freeze({ states: STATES.slice(), canonicalState: canonicalState, announce: announce, renderState: renderState, formatFreshness: formatFreshness, focusFirstError: focusFirstError }); })(window);