@absolutejs/voice 0.0.22-beta.332 → 0.0.22-beta.334

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vue/index.js CHANGED
@@ -1492,6 +1492,22 @@ var maxNumber = (values) => {
1492
1492
  var readProofTrendMaxLiveP95 = (report) => report.summary.maxLiveP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.liveLatency?.p95Ms));
1493
1493
  var readProofTrendMaxProviderP95 = (report) => report.summary.maxProviderP95Ms;
1494
1494
  var readProofTrendMaxTurnP95 = (report) => report.summary.maxTurnP95Ms ?? maxNumber(report.cycles.map((cycle) => cycle.turnLatency?.p95Ms));
1495
+ var readRuntimeChannelMetric = (report, key) => {
1496
+ const summaryValue = report.summary.runtimeChannel?.[key];
1497
+ return typeof summaryValue === "number" ? summaryValue : maxNumber(report.cycles.map((cycle) => {
1498
+ const value = cycle.runtimeChannel?.[key];
1499
+ return typeof value === "number" ? value : undefined;
1500
+ }));
1501
+ };
1502
+ var readProofTrendRuntimeChannel = (report) => ({
1503
+ maxBackpressureEvents: readRuntimeChannelMetric(report, "maxBackpressureEvents"),
1504
+ maxFirstAudioLatencyMs: readRuntimeChannelMetric(report, "maxFirstAudioLatencyMs"),
1505
+ maxInterruptionP95Ms: readRuntimeChannelMetric(report, "maxInterruptionP95Ms"),
1506
+ maxJitterMs: readRuntimeChannelMetric(report, "maxJitterMs"),
1507
+ maxTimestampDriftMs: readRuntimeChannelMetric(report, "maxTimestampDriftMs"),
1508
+ samples: report.summary.runtimeChannel?.samples ?? maxNumber(report.cycles.map((cycle) => cycle.runtimeChannel?.samples)),
1509
+ status: report.summary.runtimeChannel?.status
1510
+ });
1495
1511
  var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
1496
1512
  const issues = [];
1497
1513
  const requiredStatus = input.requireStatus ?? "pass";
@@ -1501,6 +1517,7 @@ var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
1501
1517
  const failedCycles = report.cycles.filter((cycle) => cycle.ok !== true).length;
1502
1518
  const maxLiveP95Ms = readProofTrendMaxLiveP95(report);
1503
1519
  const maxProviderP95Ms = readProofTrendMaxProviderP95(report);
1520
+ const runtimeChannel = readProofTrendRuntimeChannel(report);
1504
1521
  const maxTurnP95Ms = readProofTrendMaxTurnP95(report);
1505
1522
  if (report.status !== requiredStatus) {
1506
1523
  issues.push(`Expected proof trends status ${requiredStatus}, found ${report.status}.`);
@@ -1526,6 +1543,21 @@ var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
1526
1543
  if (input.maxTurnP95Ms !== undefined && (maxTurnP95Ms === undefined || maxTurnP95Ms > input.maxTurnP95Ms)) {
1527
1544
  issues.push(maxTurnP95Ms === undefined ? "Missing proof trends turn latency p95." : `Expected proof trends turn latency p95 at most ${String(input.maxTurnP95Ms)}ms, found ${String(maxTurnP95Ms)}ms.`);
1528
1545
  }
1546
+ if (input.maxRuntimeFirstAudioLatencyMs !== undefined && (runtimeChannel.maxFirstAudioLatencyMs === undefined || runtimeChannel.maxFirstAudioLatencyMs > input.maxRuntimeFirstAudioLatencyMs)) {
1547
+ issues.push(runtimeChannel.maxFirstAudioLatencyMs === undefined ? "Missing proof trends runtime-channel first audio latency." : `Expected proof trends runtime-channel first audio latency at most ${String(input.maxRuntimeFirstAudioLatencyMs)}ms, found ${String(runtimeChannel.maxFirstAudioLatencyMs)}ms.`);
1548
+ }
1549
+ if (input.maxRuntimeInterruptionP95Ms !== undefined && (runtimeChannel.maxInterruptionP95Ms === undefined || runtimeChannel.maxInterruptionP95Ms > input.maxRuntimeInterruptionP95Ms)) {
1550
+ issues.push(runtimeChannel.maxInterruptionP95Ms === undefined ? "Missing proof trends runtime-channel interruption p95." : `Expected proof trends runtime-channel interruption p95 at most ${String(input.maxRuntimeInterruptionP95Ms)}ms, found ${String(runtimeChannel.maxInterruptionP95Ms)}ms.`);
1551
+ }
1552
+ if (input.maxRuntimeJitterMs !== undefined && (runtimeChannel.maxJitterMs === undefined || runtimeChannel.maxJitterMs > input.maxRuntimeJitterMs)) {
1553
+ issues.push(runtimeChannel.maxJitterMs === undefined ? "Missing proof trends runtime-channel jitter." : `Expected proof trends runtime-channel jitter at most ${String(input.maxRuntimeJitterMs)}ms, found ${String(runtimeChannel.maxJitterMs)}ms.`);
1554
+ }
1555
+ if (input.maxRuntimeTimestampDriftMs !== undefined && (runtimeChannel.maxTimestampDriftMs === undefined || runtimeChannel.maxTimestampDriftMs > input.maxRuntimeTimestampDriftMs)) {
1556
+ issues.push(runtimeChannel.maxTimestampDriftMs === undefined ? "Missing proof trends runtime-channel timestamp drift." : `Expected proof trends runtime-channel timestamp drift at most ${String(input.maxRuntimeTimestampDriftMs)}ms, found ${String(runtimeChannel.maxTimestampDriftMs)}ms.`);
1557
+ }
1558
+ if (input.maxRuntimeBackpressureEvents !== undefined && (runtimeChannel.maxBackpressureEvents === undefined || runtimeChannel.maxBackpressureEvents > input.maxRuntimeBackpressureEvents)) {
1559
+ issues.push(runtimeChannel.maxBackpressureEvents === undefined ? "Missing proof trends runtime-channel backpressure events." : `Expected proof trends runtime-channel backpressure events at most ${String(input.maxRuntimeBackpressureEvents)}, found ${String(runtimeChannel.maxBackpressureEvents)}.`);
1560
+ }
1529
1561
  if (input.minLiveLatencySamples !== undefined) {
1530
1562
  const lowSamples = report.cycles.filter((cycle) => (cycle.liveLatency?.samples ?? 0) < input.minLiveLatencySamples).length;
1531
1563
  if (lowSamples > 0) {
@@ -1544,6 +1576,9 @@ var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
1544
1576
  issues.push(`Expected every proof trend cycle to have at least ${String(input.minTurnLatencySamples)} turn latency sample(s), found ${String(lowSamples)} low-sample cycle(s).`);
1545
1577
  }
1546
1578
  }
1579
+ if (input.minRuntimeChannelSamples !== undefined && (runtimeChannel.samples === undefined || runtimeChannel.samples < input.minRuntimeChannelSamples)) {
1580
+ issues.push(runtimeChannel.samples === undefined ? "Missing proof trends runtime-channel samples." : `Expected proof trends runtime-channel samples at least ${String(input.minRuntimeChannelSamples)}, found ${String(runtimeChannel.samples)}.`);
1581
+ }
1547
1582
  return {
1548
1583
  ageMs: report.ageMs,
1549
1584
  cycles,
@@ -1551,6 +1586,7 @@ var evaluateVoiceProofTrendEvidence = (report, input = {}) => {
1551
1586
  issues,
1552
1587
  maxLiveP95Ms,
1553
1588
  maxProviderP95Ms,
1589
+ runtimeChannel,
1554
1590
  maxTurnP95Ms,
1555
1591
  ok: issues.length === 0,
1556
1592
  status: report.status
@@ -1563,6 +1599,162 @@ var assertVoiceProofTrendEvidence = (report, input = {}) => {
1563
1599
  }
1564
1600
  return assertion;
1565
1601
  };
1602
+ var DEFAULT_RECOMMENDATION_BUDGETS = {
1603
+ maxLiveP95Ms: 800,
1604
+ maxProviderP95Ms: 1000,
1605
+ maxRuntimeBackpressureEvents: 0,
1606
+ maxRuntimeFirstAudioLatencyMs: 600,
1607
+ maxRuntimeInterruptionP95Ms: 300,
1608
+ maxRuntimeJitterMs: 30,
1609
+ maxRuntimeTimestampDriftMs: 800,
1610
+ maxTurnP95Ms: 700
1611
+ };
1612
+ var withinBudget = (value, budget) => typeof value === "number" && Number.isFinite(value) && value <= budget;
1613
+ var recommendationStatusRank = {
1614
+ pass: 0,
1615
+ warn: 1,
1616
+ fail: 2
1617
+ };
1618
+ var worstRecommendationStatus = (recommendations) => recommendations.reduce((status, recommendation) => recommendationStatusRank[recommendation.status] > recommendationStatusRank[status] ? recommendation.status : status, "pass");
1619
+ var buildVoiceProofTrendRecommendationReport = (report, options = {}) => {
1620
+ const budgets = { ...DEFAULT_RECOMMENDATION_BUDGETS, ...options };
1621
+ const maxLiveP95Ms = readProofTrendMaxLiveP95(report);
1622
+ const maxProviderP95Ms = readProofTrendMaxProviderP95(report);
1623
+ const maxTurnP95Ms = readProofTrendMaxTurnP95(report);
1624
+ const runtimeChannel = readProofTrendRuntimeChannel(report);
1625
+ const recommendations = [];
1626
+ const issues = [];
1627
+ if (report.ok !== true) {
1628
+ issues.push(`Proof trend report is ${report.status}; recommendations need a fresh passing trend artifact.`);
1629
+ }
1630
+ recommendations.push({
1631
+ evidence: {
1632
+ budgetMs: budgets.maxProviderP95Ms,
1633
+ providerP95Ms: maxProviderP95Ms
1634
+ },
1635
+ nextMove: withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep the current provider route for latency-sensitive turns and keep collecting sustained proof." : "Route latency-sensitive turns to a faster provider profile or tighten fallback/circuit-breaker budgets before promotion.",
1636
+ recommendation: withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "Keep current provider path" : "Change provider routing for latency-sensitive traffic",
1637
+ status: withinBudget(maxProviderP95Ms, budgets.maxProviderP95Ms) ? "pass" : maxProviderP95Ms === undefined ? "fail" : "warn",
1638
+ surface: "provider-path"
1639
+ });
1640
+ const runtimePass = withinBudget(runtimeChannel.maxFirstAudioLatencyMs, budgets.maxRuntimeFirstAudioLatencyMs) && withinBudget(runtimeChannel.maxInterruptionP95Ms, budgets.maxRuntimeInterruptionP95Ms) && withinBudget(runtimeChannel.maxJitterMs, budgets.maxRuntimeJitterMs) && withinBudget(runtimeChannel.maxTimestampDriftMs, budgets.maxRuntimeTimestampDriftMs) && withinBudget(runtimeChannel.maxBackpressureEvents, budgets.maxRuntimeBackpressureEvents);
1641
+ recommendations.push({
1642
+ evidence: {
1643
+ backpressureEvents: runtimeChannel.maxBackpressureEvents,
1644
+ firstAudioBudgetMs: budgets.maxRuntimeFirstAudioLatencyMs,
1645
+ firstAudioMs: runtimeChannel.maxFirstAudioLatencyMs,
1646
+ interruptionBudgetMs: budgets.maxRuntimeInterruptionP95Ms,
1647
+ interruptionP95Ms: runtimeChannel.maxInterruptionP95Ms,
1648
+ jitterBudgetMs: budgets.maxRuntimeJitterMs,
1649
+ jitterMs: runtimeChannel.maxJitterMs,
1650
+ samples: runtimeChannel.samples,
1651
+ timestampDriftMs: runtimeChannel.maxTimestampDriftMs
1652
+ },
1653
+ nextMove: runtimePass ? "Keep the current runtime-channel settings and use this artifact as the deploy gate baseline." : "Tune capture/output format, buffering, interruption threshold, or transport backpressure before promoting this runtime path.",
1654
+ recommendation: runtimePass ? "Keep current runtime channel" : "Tune runtime channel before promotion",
1655
+ status: runtimePass ? "pass" : runtimeChannel.samples === undefined ? "fail" : "warn",
1656
+ surface: "runtime-channel"
1657
+ });
1658
+ recommendations.push({
1659
+ evidence: {
1660
+ budgetMs: budgets.maxLiveP95Ms,
1661
+ liveP95Ms: maxLiveP95Ms
1662
+ },
1663
+ nextMove: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "Keep browser live-latency defaults and continue watching long-window drift." : "Tune browser streaming, chunking, or readiness thresholds before release.",
1664
+ recommendation: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "Keep live-latency settings" : "Tune live-latency path",
1665
+ status: withinBudget(maxLiveP95Ms, budgets.maxLiveP95Ms) ? "pass" : maxLiveP95Ms === undefined ? "fail" : "warn",
1666
+ surface: "live-latency"
1667
+ });
1668
+ recommendations.push({
1669
+ evidence: {
1670
+ budgetMs: budgets.maxTurnP95Ms,
1671
+ turnP95Ms: maxTurnP95Ms
1672
+ },
1673
+ nextMove: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "Keep current turn pipeline defaults." : "Reduce tool/provider latency or split the turn pipeline before promotion.",
1674
+ recommendation: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "Keep turn pipeline" : "Tune turn pipeline",
1675
+ status: withinBudget(maxTurnP95Ms, budgets.maxTurnP95Ms) ? "pass" : maxTurnP95Ms === undefined ? "fail" : "warn",
1676
+ surface: "turn-latency"
1677
+ });
1678
+ const status = issues.length > 0 ? "fail" : worstRecommendationStatus(recommendations);
1679
+ return {
1680
+ generatedAt: new Date().toISOString(),
1681
+ issues,
1682
+ ok: status !== "fail",
1683
+ recommendations,
1684
+ source: report.source || report.outputDir || report.runId || "proof-trends",
1685
+ status,
1686
+ summary: {
1687
+ keepCurrentProviderPath: recommendations.find((item) => item.surface === "provider-path")?.status === "pass",
1688
+ keepCurrentRuntimeChannel: recommendations.find((item) => item.surface === "runtime-channel")?.status === "pass",
1689
+ recommendedActions: recommendations.filter((item) => item.status !== "pass").length
1690
+ }
1691
+ };
1692
+ };
1693
+ var escapeHtml5 = (value) => String(value).replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1694
+ var escapeMarkdown = (value) => value.replaceAll("|", "\\|");
1695
+ var renderVoiceProofTrendRecommendationMarkdown = (report, title = "Voice Provider Runtime Recommendations") => [
1696
+ `# ${title}`,
1697
+ "",
1698
+ `- Status: ${report.status}`,
1699
+ `- Source: ${report.source}`,
1700
+ `- Recommended actions: ${String(report.summary.recommendedActions)}`,
1701
+ "",
1702
+ "| Surface | Status | Recommendation | Next move |",
1703
+ "| --- | --- | --- | --- |",
1704
+ ...report.recommendations.map((recommendation) => `| ${escapeMarkdown(recommendation.surface)} | ${recommendation.status} | ${escapeMarkdown(recommendation.recommendation)} | ${escapeMarkdown(recommendation.nextMove)} |`),
1705
+ "",
1706
+ "## Issues",
1707
+ "",
1708
+ ...report.issues.length ? report.issues.map((issue) => `- ${issue}`) : ["- None"]
1709
+ ].join(`
1710
+ `);
1711
+ var renderVoiceProofTrendRecommendationHTML = (report, title = "Voice Provider Runtime Recommendations") => {
1712
+ const cards = report.recommendations.map((recommendation) => `<article class="${escapeHtml5(recommendation.status)}"><p class="eyebrow">${escapeHtml5(recommendation.surface)} \xB7 ${escapeHtml5(recommendation.status)}</p><h2>${escapeHtml5(recommendation.recommendation)}</h2><p>${escapeHtml5(recommendation.nextMove)}</p><pre>${escapeHtml5(JSON.stringify(recommendation.evidence, null, 2))}</pre></article>`).join("");
1713
+ const issues = report.issues.length === 0 ? "<li>None</li>" : report.issues.map((issue) => `<li>${escapeHtml5(issue)}</li>`).join("");
1714
+ return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" /><title>${escapeHtml5(title)}</title><style>body{background:#101418;color:#f7f3e8;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1120px;padding:32px}.hero,article{background:#17201d;border:1px solid #2e3d36;border-radius:24px;margin-bottom:16px;padding:22px}.hero{background:linear-gradient(135deg,rgba(20,184,166,.18),rgba(245,158,11,.12))}.eyebrow{color:#5eead4;font-weight:900;letter-spacing:.1em;text-transform:uppercase}h1{font-size:clamp(2.2rem,6vw,4.7rem);letter-spacing:-.06em;line-height:.92;margin:.2rem 0 1rem}.summary{display:flex;flex-wrap:wrap;gap:10px}.pill{border:1px solid #42534a;border-radius:999px;padding:8px 12px}.pass{border-color:rgba(34,197,94,.55)}.warn{border-color:rgba(245,158,11,.7)}.fail{border-color:rgba(239,68,68,.75)}pre{background:#0b1110;border-radius:14px;overflow:auto;padding:12px}a{color:#5eead4}</style></head><body><main><section class="hero"><p class="eyebrow">Sustained proof recommendations</p><h1>${escapeHtml5(title)}</h1><p>Generated ${escapeHtml5(report.generatedAt)} from ${escapeHtml5(report.source)}.</p><div class="summary"><span class="pill">Status ${escapeHtml5(report.status)}</span><span class="pill">Provider ${report.summary.keepCurrentProviderPath ? "keep" : "change"}</span><span class="pill">Runtime ${report.summary.keepCurrentRuntimeChannel ? "keep" : "tune"}</span><span class="pill">${String(report.summary.recommendedActions)} action(s)</span></div></section>${cards}<section class="hero"><h2>Issues</h2><ul>${issues}</ul></section></main></body></html>`;
1715
+ };
1716
+ var createVoiceProofTrendRecommendationRoutes = (options) => {
1717
+ const path = options.path ?? "/api/voice/proof-trend-recommendations";
1718
+ const htmlPath = options.htmlPath === undefined ? "/voice/proof-trend-recommendations" : options.htmlPath;
1719
+ const markdownPath = options.markdownPath === undefined ? "/voice/proof-trend-recommendations.md" : options.markdownPath;
1720
+ const title = options.title ?? "Voice Provider Runtime Recommendations";
1721
+ const routes = new Elysia({
1722
+ name: options.name ?? "absolutejs-voice-proof-trend-recommendations"
1723
+ });
1724
+ const loadReport = async () => {
1725
+ const value = options.source !== undefined ? typeof options.source === "function" ? await options.source() : options.source : options.jsonPath ? await readVoiceProofTrendReportFile(options.jsonPath, {
1726
+ maxAgeMs: options.maxAgeMs
1727
+ }) : buildEmptyVoiceProofTrendReport("", options.maxAgeMs);
1728
+ return buildVoiceProofTrendRecommendationReport(normalizeVoiceProofTrendReport(value, {
1729
+ maxAgeMs: options.maxAgeMs,
1730
+ source: options.jsonPath
1731
+ }), options);
1732
+ };
1733
+ routes.get(path, async () => Response.json(await loadReport(), { headers: options.headers }));
1734
+ if (htmlPath !== false) {
1735
+ routes.get(htmlPath, async () => {
1736
+ const report = await loadReport();
1737
+ return new Response(renderVoiceProofTrendRecommendationHTML(report, title), {
1738
+ headers: {
1739
+ "content-type": "text/html; charset=utf-8",
1740
+ ...Object.fromEntries(new Headers(options.headers))
1741
+ }
1742
+ });
1743
+ });
1744
+ }
1745
+ if (markdownPath !== false) {
1746
+ routes.get(markdownPath, async () => {
1747
+ const report = await loadReport();
1748
+ return new Response(renderVoiceProofTrendRecommendationMarkdown(report, title), {
1749
+ headers: {
1750
+ "content-type": "text/markdown; charset=utf-8",
1751
+ ...Object.fromEntries(new Headers(options.headers))
1752
+ }
1753
+ });
1754
+ });
1755
+ }
1756
+ return routes;
1757
+ };
1566
1758
  var createVoiceProofTrendRoutes = (options) => {
1567
1759
  const path = options.path ?? "/api/voice/proof-trends";
1568
1760
  const routes = new Elysia({
@@ -1684,7 +1876,7 @@ var DEFAULT_LINKS2 = [
1684
1876
  { href: "/voice/proof-trends", label: "Trend page" },
1685
1877
  { href: "/api/voice/proof-trends", label: "Trend JSON" }
1686
1878
  ];
1687
- var escapeHtml5 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1879
+ var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1688
1880
  var formatMs = (value) => typeof value === "number" && Number.isFinite(value) ? `${Math.round(value)}ms` : "n/a";
1689
1881
  var statusLabel = (report) => {
1690
1882
  if (!report) {
@@ -1734,19 +1926,19 @@ var createVoiceProofTrendsViewModel = (snapshot, options = {}) => {
1734
1926
  var renderVoiceProofTrendsHTML = (snapshot, options = {}) => {
1735
1927
  const model = createVoiceProofTrendsViewModel(snapshot, options);
1736
1928
  const metrics = model.metrics.length ? `<div class="absolute-voice-proof-trends__metrics">${model.metrics.map((metric) => `<article>
1737
- <span>${escapeHtml5(metric.label)}</span>
1738
- <strong>${escapeHtml5(metric.value)}</strong>
1739
- </article>`).join("")}</div>` : `<p class="absolute-voice-proof-trends__empty">${model.error ? escapeHtml5(model.error) : "Run the sustained proof trends script to populate evidence."}</p>`;
1740
- const links = model.links.length ? `<p class="absolute-voice-proof-trends__links">${model.links.map((link) => `<a href="${escapeHtml5(link.href)}">${escapeHtml5(link.label)}</a>`).join("")}</p>` : "";
1741
- return `<section class="absolute-voice-proof-trends absolute-voice-proof-trends--${escapeHtml5(model.status)}">
1929
+ <span>${escapeHtml6(metric.label)}</span>
1930
+ <strong>${escapeHtml6(metric.value)}</strong>
1931
+ </article>`).join("")}</div>` : `<p class="absolute-voice-proof-trends__empty">${model.error ? escapeHtml6(model.error) : "Run the sustained proof trends script to populate evidence."}</p>`;
1932
+ const links = model.links.length ? `<p class="absolute-voice-proof-trends__links">${model.links.map((link) => `<a href="${escapeHtml6(link.href)}">${escapeHtml6(link.label)}</a>`).join("")}</p>` : "";
1933
+ return `<section class="absolute-voice-proof-trends absolute-voice-proof-trends--${escapeHtml6(model.status)}">
1742
1934
  <header class="absolute-voice-proof-trends__header">
1743
- <span class="absolute-voice-proof-trends__eyebrow">${escapeHtml5(model.title)}</span>
1744
- <strong class="absolute-voice-proof-trends__label">${escapeHtml5(model.label)}</strong>
1935
+ <span class="absolute-voice-proof-trends__eyebrow">${escapeHtml6(model.title)}</span>
1936
+ <strong class="absolute-voice-proof-trends__label">${escapeHtml6(model.label)}</strong>
1745
1937
  </header>
1746
- <p class="absolute-voice-proof-trends__description">${escapeHtml5(model.description)}</p>
1938
+ <p class="absolute-voice-proof-trends__description">${escapeHtml6(model.description)}</p>
1747
1939
  ${metrics}
1748
1940
  ${links}
1749
- ${model.error ? `<p class="absolute-voice-proof-trends__error">${escapeHtml5(model.error)}</p>` : ""}
1941
+ ${model.error ? `<p class="absolute-voice-proof-trends__error">${escapeHtml6(model.error)}</p>` : ""}
1750
1942
  </section>`;
1751
1943
  };
1752
1944
  var getVoiceProofTrendsCSS = () => `.absolute-voice-proof-trends{border:1px solid #99f6e4;border-radius:20px;background:#f0fdfa;color:#0f172a;padding:18px;box-shadow:0 18px 40px rgba(13,148,136,.12);font-family:inherit}.absolute-voice-proof-trends--warning,.absolute-voice-proof-trends--error{border-color:#f2a7a7;background:#fff7f4}.absolute-voice-proof-trends__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-proof-trends__eyebrow{color:#0f766e;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-proof-trends__label{font-size:24px;line-height:1}.absolute-voice-proof-trends__description,.absolute-voice-proof-trends__empty{color:#475569}.absolute-voice-proof-trends__metrics{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));margin-top:14px}.absolute-voice-proof-trends__metrics article{background:#fff;border:1px solid #ccfbf1;border-radius:16px;padding:12px}.absolute-voice-proof-trends__metrics span{color:#64748b;display:block;font-size:12px;font-weight:800;text-transform:uppercase}.absolute-voice-proof-trends__metrics strong{display:block;font-size:20px;margin-top:4px}.absolute-voice-proof-trends__links{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0 0}.absolute-voice-proof-trends__links a{border:1px solid #99f6e4;border-radius:999px;color:#0f766e;font-weight:800;padding:6px 10px;text-decoration:none}.absolute-voice-proof-trends__error{color:#9f1239;font-weight:700}`;
@@ -1954,7 +2146,7 @@ var DEFAULT_LINKS3 = [
1954
2146
  { href: "/production-readiness", label: "Readiness page" },
1955
2147
  { href: "/voice/slo-readiness-thresholds", label: "Gate thresholds" }
1956
2148
  ];
1957
- var escapeHtml6 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2149
+ var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
1958
2150
  var formatExplanationValue = (value, unit) => {
1959
2151
  if (value === undefined || value === null) {
1960
2152
  return "n/a";
@@ -1995,23 +2187,23 @@ var createVoiceReadinessFailuresViewModel = (snapshot, options = {}) => {
1995
2187
  };
1996
2188
  var renderVoiceReadinessFailuresHTML = (snapshot, options = {}) => {
1997
2189
  const model = createVoiceReadinessFailuresViewModel(snapshot, options);
1998
- const failures = model.failures.length ? `<div class="absolute-voice-readiness-failures__items">${model.failures.map((failure) => `<article class="absolute-voice-readiness-failures__item absolute-voice-readiness-failures__item--${escapeHtml6(failure.status)}">
1999
- <span>${escapeHtml6(failure.status.toUpperCase())}</span>
2000
- <strong>${escapeHtml6(failure.label)}</strong>
2001
- <p>Observed ${escapeHtml6(failure.observed)} against ${escapeHtml6(failure.thresholdLabel)} ${escapeHtml6(failure.threshold)}.</p>
2002
- <p>${escapeHtml6(failure.remediation)}</p>
2003
- <p class="absolute-voice-readiness-failures__links">${failure.evidenceHref ? `<a href="${escapeHtml6(failure.evidenceHref)}">Evidence</a>` : ""}${failure.sourceHref ? `<a href="${escapeHtml6(failure.sourceHref)}">Threshold source</a>` : ""}</p>
2004
- </article>`).join("")}</div>` : `<p class="absolute-voice-readiness-failures__empty">${model.error ? escapeHtml6(model.error) : "No calibrated readiness gate explanations are open."}</p>`;
2005
- const links = model.links.length ? `<p class="absolute-voice-readiness-failures__links">${model.links.map((link) => `<a href="${escapeHtml6(link.href)}">${escapeHtml6(link.label)}</a>`).join("")}</p>` : "";
2006
- return `<section class="absolute-voice-readiness-failures absolute-voice-readiness-failures--${escapeHtml6(model.status)}">
2190
+ const failures = model.failures.length ? `<div class="absolute-voice-readiness-failures__items">${model.failures.map((failure) => `<article class="absolute-voice-readiness-failures__item absolute-voice-readiness-failures__item--${escapeHtml7(failure.status)}">
2191
+ <span>${escapeHtml7(failure.status.toUpperCase())}</span>
2192
+ <strong>${escapeHtml7(failure.label)}</strong>
2193
+ <p>Observed ${escapeHtml7(failure.observed)} against ${escapeHtml7(failure.thresholdLabel)} ${escapeHtml7(failure.threshold)}.</p>
2194
+ <p>${escapeHtml7(failure.remediation)}</p>
2195
+ <p class="absolute-voice-readiness-failures__links">${failure.evidenceHref ? `<a href="${escapeHtml7(failure.evidenceHref)}">Evidence</a>` : ""}${failure.sourceHref ? `<a href="${escapeHtml7(failure.sourceHref)}">Threshold source</a>` : ""}</p>
2196
+ </article>`).join("")}</div>` : `<p class="absolute-voice-readiness-failures__empty">${model.error ? escapeHtml7(model.error) : "No calibrated readiness gate explanations are open."}</p>`;
2197
+ const links = model.links.length ? `<p class="absolute-voice-readiness-failures__links">${model.links.map((link) => `<a href="${escapeHtml7(link.href)}">${escapeHtml7(link.label)}</a>`).join("")}</p>` : "";
2198
+ return `<section class="absolute-voice-readiness-failures absolute-voice-readiness-failures--${escapeHtml7(model.status)}">
2007
2199
  <header class="absolute-voice-readiness-failures__header">
2008
- <span class="absolute-voice-readiness-failures__eyebrow">${escapeHtml6(model.title)}</span>
2009
- <strong class="absolute-voice-readiness-failures__label">${escapeHtml6(model.label)}</strong>
2200
+ <span class="absolute-voice-readiness-failures__eyebrow">${escapeHtml7(model.title)}</span>
2201
+ <strong class="absolute-voice-readiness-failures__label">${escapeHtml7(model.label)}</strong>
2010
2202
  </header>
2011
- <p class="absolute-voice-readiness-failures__description">${escapeHtml6(model.description)}</p>
2203
+ <p class="absolute-voice-readiness-failures__description">${escapeHtml7(model.description)}</p>
2012
2204
  ${failures}
2013
2205
  ${links}
2014
- ${model.error ? `<p class="absolute-voice-readiness-failures__error">${escapeHtml6(model.error)}</p>` : ""}
2206
+ ${model.error ? `<p class="absolute-voice-readiness-failures__error">${escapeHtml7(model.error)}</p>` : ""}
2015
2207
  </section>`;
2016
2208
  };
2017
2209
  var getVoiceReadinessFailuresCSS = () => `.absolute-voice-readiness-failures{border:1px solid #fed7aa;border-radius:20px;background:#fff7ed;color:#1c1917;padding:18px;box-shadow:0 18px 40px rgba(234,88,12,.12);font-family:inherit}.absolute-voice-readiness-failures--ready{border-color:#86efac;background:#f0fdf4}.absolute-voice-readiness-failures--error{border-color:#fda4af;background:#fff1f2}.absolute-voice-readiness-failures__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-readiness-failures__eyebrow{color:#9a3412;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-readiness-failures__label{font-size:24px;line-height:1}.absolute-voice-readiness-failures__description,.absolute-voice-readiness-failures__empty{color:#57534e}.absolute-voice-readiness-failures__items{display:grid;gap:10px;margin-top:14px}.absolute-voice-readiness-failures__item{background:white;border:1px solid #fed7aa;border-radius:16px;padding:12px}.absolute-voice-readiness-failures__item--fail{border-color:#fb7185}.absolute-voice-readiness-failures__item span{color:#9a3412;display:block;font-size:12px;font-weight:900;text-transform:uppercase}.absolute-voice-readiness-failures__item strong{display:block;font-size:18px;margin-top:4px}.absolute-voice-readiness-failures__item p{margin:.45rem 0 0}.absolute-voice-readiness-failures__links{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0 0}.absolute-voice-readiness-failures__links a{border:1px solid #fdba74;border-radius:999px;color:#9a3412;font-weight:800;padding:6px 10px;text-decoration:none}.absolute-voice-readiness-failures__error{color:#9f1239;font-weight:700}`;
@@ -2228,7 +2420,7 @@ var createVoiceProviderSimulationControlsStore = (options) => {
2228
2420
  };
2229
2421
 
2230
2422
  // src/client/providerSimulationControlsWidget.ts
2231
- var escapeHtml7 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2423
+ var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2232
2424
  var formatKind = (kind) => (kind ?? "stt").toUpperCase();
2233
2425
  var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
2234
2426
  const configuredProviders = options.providers.filter((provider) => provider.configured !== false);
@@ -2248,18 +2440,18 @@ var createVoiceProviderSimulationControlsViewModel = (snapshot, options) => {
2248
2440
  };
2249
2441
  var renderVoiceProviderSimulationControlsHTML = (snapshot, options) => {
2250
2442
  const model = createVoiceProviderSimulationControlsViewModel(snapshot, options);
2251
- const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml7(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml7(provider.provider)} ${escapeHtml7(formatKind(options.kind))} failure</button>`).join("");
2252
- const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml7(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml7(provider.provider)} recovered</button>`).join("");
2443
+ const failureButtons = model.failureProviders.map((provider) => `<button type="button" data-voice-provider-fail="${escapeHtml8(provider.provider)}"${!model.canSimulateFailure || snapshot.isRunning ? " disabled" : ""}>Simulate ${escapeHtml8(provider.provider)} ${escapeHtml8(formatKind(options.kind))} failure</button>`).join("");
2444
+ const recoveryButtons = model.providers.map((provider) => `<button type="button" data-voice-provider-recover="${escapeHtml8(provider.provider)}"${snapshot.isRunning ? " disabled" : ""}>Mark ${escapeHtml8(provider.provider)} recovered</button>`).join("");
2253
2445
  return `<section class="absolute-voice-provider-simulation absolute-voice-provider-simulation--${snapshot.error ? "error" : snapshot.isRunning ? "running" : "ready"}">
2254
2446
  <header class="absolute-voice-provider-simulation__header">
2255
- <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml7(model.title)}</span>
2256
- <strong class="absolute-voice-provider-simulation__label">${escapeHtml7(model.label)}</strong>
2447
+ <span class="absolute-voice-provider-simulation__eyebrow">${escapeHtml8(model.title)}</span>
2448
+ <strong class="absolute-voice-provider-simulation__label">${escapeHtml8(model.label)}</strong>
2257
2449
  </header>
2258
- <p class="absolute-voice-provider-simulation__description">${escapeHtml7(model.description)}</p>
2259
- ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml7(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
2450
+ <p class="absolute-voice-provider-simulation__description">${escapeHtml8(model.description)}</p>
2451
+ ${model.canSimulateFailure ? "" : `<p class="absolute-voice-provider-simulation__empty">${escapeHtml8(options.fallbackRequiredMessage ?? "Configure fallback providers before simulating failure.")}</p>`}
2260
2452
  <div class="absolute-voice-provider-simulation__actions">${failureButtons}${recoveryButtons}</div>
2261
- ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml7(snapshot.error)}</p>` : ""}
2262
- ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml7(model.resultText)}</pre>` : ""}
2453
+ ${snapshot.error ? `<p class="absolute-voice-provider-simulation__error">${escapeHtml8(snapshot.error)}</p>` : ""}
2454
+ ${model.resultText ? `<pre class="absolute-voice-provider-simulation__result">${escapeHtml8(model.resultText)}</pre>` : ""}
2263
2455
  </section>`;
2264
2456
  };
2265
2457
  var bindVoiceProviderSimulationControls = (element, store) => {
@@ -2520,7 +2712,7 @@ var createVoiceProviderCapabilitiesStore = (path = "/api/provider-capabilities",
2520
2712
  // src/client/providerCapabilitiesWidget.ts
2521
2713
  var DEFAULT_TITLE7 = "Provider Capabilities";
2522
2714
  var DEFAULT_DESCRIPTION7 = "Configured, selected, and healthy voice providers for this deployment.";
2523
- var escapeHtml8 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2715
+ var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2524
2716
  var formatProvider = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
2525
2717
  var formatKind2 = (kind) => kind.toUpperCase();
2526
2718
  var formatStatus2 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
@@ -2575,25 +2767,25 @@ var createVoiceProviderCapabilitiesViewModel = (snapshot, options = {}) => {
2575
2767
  };
2576
2768
  var renderVoiceProviderCapabilitiesHTML = (snapshot, options = {}) => {
2577
2769
  const model = createVoiceProviderCapabilitiesViewModel(snapshot, options);
2578
- const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml8(capability.status)}">
2770
+ const capabilities = model.capabilities.length ? `<div class="absolute-voice-provider-capabilities__providers">${model.capabilities.map((capability) => `<article class="absolute-voice-provider-capabilities__provider absolute-voice-provider-capabilities__provider--${escapeHtml9(capability.status)}">
2579
2771
  <header>
2580
- <strong>${escapeHtml8(capability.label)}</strong>
2581
- <span>${escapeHtml8(formatStatus2(capability.status))}</span>
2772
+ <strong>${escapeHtml9(capability.label)}</strong>
2773
+ <span>${escapeHtml9(formatStatus2(capability.status))}</span>
2582
2774
  </header>
2583
- <p>${escapeHtml8(capability.detail)}</p>
2775
+ <p>${escapeHtml9(capability.detail)}</p>
2584
2776
  <dl>${capability.rows.map((row) => `<div>
2585
- <dt>${escapeHtml8(row.label)}</dt>
2586
- <dd>${escapeHtml8(row.value)}</dd>
2777
+ <dt>${escapeHtml9(row.label)}</dt>
2778
+ <dd>${escapeHtml9(row.value)}</dd>
2587
2779
  </div>`).join("")}</dl>
2588
2780
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-capabilities__empty">Configure provider capabilities to see deployment coverage.</p>';
2589
- return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml8(model.status)}">
2781
+ return `<section class="absolute-voice-provider-capabilities absolute-voice-provider-capabilities--${escapeHtml9(model.status)}">
2590
2782
  <header class="absolute-voice-provider-capabilities__header">
2591
- <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml8(model.title)}</span>
2592
- <strong class="absolute-voice-provider-capabilities__label">${escapeHtml8(model.label)}</strong>
2783
+ <span class="absolute-voice-provider-capabilities__eyebrow">${escapeHtml9(model.title)}</span>
2784
+ <strong class="absolute-voice-provider-capabilities__label">${escapeHtml9(model.label)}</strong>
2593
2785
  </header>
2594
- <p class="absolute-voice-provider-capabilities__description">${escapeHtml8(model.description)}</p>
2786
+ <p class="absolute-voice-provider-capabilities__description">${escapeHtml9(model.description)}</p>
2595
2787
  ${capabilities}
2596
- ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml8(model.error)}</p>` : ""}
2788
+ ${model.error ? `<p class="absolute-voice-provider-capabilities__error">${escapeHtml9(model.error)}</p>` : ""}
2597
2789
  </section>`;
2598
2790
  };
2599
2791
  var getVoiceProviderCapabilitiesCSS = () => `.absolute-voice-provider-capabilities{border:1px solid #bfd7ea;border-radius:20px;background:#f6fbff;color:#08131f;padding:18px;box-shadow:0 18px 40px rgba(14,51,78,.12);font-family:inherit}.absolute-voice-provider-capabilities--error,.absolute-voice-provider-capabilities--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-capabilities__header,.absolute-voice-provider-capabilities__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-capabilities__eyebrow{color:#255f85;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-capabilities__label{font-size:24px;line-height:1}.absolute-voice-provider-capabilities__description,.absolute-voice-provider-capabilities__provider p,.absolute-voice-provider-capabilities__provider dt,.absolute-voice-provider-capabilities__empty{color:#405467}.absolute-voice-provider-capabilities__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-capabilities__provider{background:#fff;border:1px solid #d7e7f3;border-radius:16px;padding:14px}.absolute-voice-provider-capabilities__provider--selected,.absolute-voice-provider-capabilities__provider--healthy{border-color:#86efac}.absolute-voice-provider-capabilities__provider--degraded,.absolute-voice-provider-capabilities__provider--rate-limited,.absolute-voice-provider-capabilities__provider--suppressed,.absolute-voice-provider-capabilities__provider--unconfigured{border-color:#f2a7a7}.absolute-voice-provider-capabilities__provider p{margin:10px 0}.absolute-voice-provider-capabilities__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-capabilities__provider div{background:#f6fbff;border:1px solid #d7e7f3;border-radius:12px;padding:8px}.absolute-voice-provider-capabilities__provider dt{font-size:12px}.absolute-voice-provider-capabilities__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-capabilities__empty{margin:14px 0 0}.absolute-voice-provider-capabilities__error{color:#9f1239;font-weight:700}`;
@@ -2850,7 +3042,7 @@ function useVoiceProviderContracts(path = "/api/provider-contracts", options = {
2850
3042
  // src/client/providerContractsWidget.ts
2851
3043
  var DEFAULT_TITLE8 = "Provider Contracts";
2852
3044
  var DEFAULT_DESCRIPTION8 = "Production contract coverage for provider env, latency, fallback, streaming, and capabilities.";
2853
- var escapeHtml9 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3045
+ var escapeHtml10 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
2854
3046
  var formatProvider2 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
2855
3047
  var formatStatus3 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
2856
3048
  var contractDetail = (row) => {
@@ -2894,26 +3086,26 @@ var createVoiceProviderContractsViewModel = (snapshot, options = {}) => {
2894
3086
  };
2895
3087
  var renderVoiceProviderContractsHTML = (snapshot, options = {}) => {
2896
3088
  const model = createVoiceProviderContractsViewModel(snapshot, options);
2897
- const rows = model.rows.length ? `<div class="absolute-voice-provider-contracts__rows">${model.rows.map((row) => `<article class="absolute-voice-provider-contracts__row absolute-voice-provider-contracts__row--${escapeHtml9(row.status)}">
3089
+ const rows = model.rows.length ? `<div class="absolute-voice-provider-contracts__rows">${model.rows.map((row) => `<article class="absolute-voice-provider-contracts__row absolute-voice-provider-contracts__row--${escapeHtml10(row.status)}">
2898
3090
  <header>
2899
- <strong>${escapeHtml9(row.label)}</strong>
2900
- <span>${escapeHtml9(formatStatus3(row.status))}</span>
3091
+ <strong>${escapeHtml10(row.label)}</strong>
3092
+ <span>${escapeHtml10(formatStatus3(row.status))}</span>
2901
3093
  </header>
2902
- <p>${escapeHtml9(row.detail)}</p>
2903
- ${row.remediations.length ? `<ul class="absolute-voice-provider-contracts__remediations">${row.remediations.map((remediation) => `<li>${remediation.href ? `<a href="${escapeHtml9(remediation.href)}">${escapeHtml9(remediation.label)}</a>` : `<strong>${escapeHtml9(remediation.label)}</strong>`}<span>${escapeHtml9(remediation.detail)}</span></li>`).join("")}</ul>` : ""}
3094
+ <p>${escapeHtml10(row.detail)}</p>
3095
+ ${row.remediations.length ? `<ul class="absolute-voice-provider-contracts__remediations">${row.remediations.map((remediation) => `<li>${remediation.href ? `<a href="${escapeHtml10(remediation.href)}">${escapeHtml10(remediation.label)}</a>` : `<strong>${escapeHtml10(remediation.label)}</strong>`}<span>${escapeHtml10(remediation.detail)}</span></li>`).join("")}</ul>` : ""}
2904
3096
  <dl>${row.rows.map((item) => `<div>
2905
- <dt>${escapeHtml9(item.label)}</dt>
2906
- <dd>${escapeHtml9(item.value)}</dd>
3097
+ <dt>${escapeHtml10(item.label)}</dt>
3098
+ <dd>${escapeHtml10(item.value)}</dd>
2907
3099
  </div>`).join("")}</dl>
2908
3100
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-contracts__empty">Configure provider contracts to see production coverage.</p>';
2909
- return `<section class="absolute-voice-provider-contracts absolute-voice-provider-contracts--${escapeHtml9(model.status)}">
3101
+ return `<section class="absolute-voice-provider-contracts absolute-voice-provider-contracts--${escapeHtml10(model.status)}">
2910
3102
  <header class="absolute-voice-provider-contracts__header">
2911
- <span class="absolute-voice-provider-contracts__eyebrow">${escapeHtml9(model.title)}</span>
2912
- <strong class="absolute-voice-provider-contracts__label">${escapeHtml9(model.label)}</strong>
3103
+ <span class="absolute-voice-provider-contracts__eyebrow">${escapeHtml10(model.title)}</span>
3104
+ <strong class="absolute-voice-provider-contracts__label">${escapeHtml10(model.label)}</strong>
2913
3105
  </header>
2914
- <p class="absolute-voice-provider-contracts__description">${escapeHtml9(model.description)}</p>
3106
+ <p class="absolute-voice-provider-contracts__description">${escapeHtml10(model.description)}</p>
2915
3107
  ${rows}
2916
- ${model.error ? `<p class="absolute-voice-provider-contracts__error">${escapeHtml9(model.error)}</p>` : ""}
3108
+ ${model.error ? `<p class="absolute-voice-provider-contracts__error">${escapeHtml10(model.error)}</p>` : ""}
2917
3109
  </section>`;
2918
3110
  };
2919
3111
  var getVoiceProviderContractsCSS = () => `.absolute-voice-provider-contracts{border:1px solid #b8dcc7;border-radius:20px;background:#f7fff9;color:#09140d;padding:18px;box-shadow:0 18px 40px rgba(21,83,45,.12);font-family:inherit}.absolute-voice-provider-contracts--error,.absolute-voice-provider-contracts--warning{border-color:#f2a7a7;background:#fff7f4}.absolute-voice-provider-contracts__header,.absolute-voice-provider-contracts__row header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-contracts__eyebrow{color:#166534;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-contracts__label{font-size:24px;line-height:1}.absolute-voice-provider-contracts__description,.absolute-voice-provider-contracts__row p,.absolute-voice-provider-contracts__row dt,.absolute-voice-provider-contracts__empty{color:#405448}.absolute-voice-provider-contracts__rows{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-contracts__row{background:#fff;border:1px solid #d6eadb;border-radius:16px;padding:14px}.absolute-voice-provider-contracts__row--pass{border-color:#86efac}.absolute-voice-provider-contracts__row--warn,.absolute-voice-provider-contracts__row--fail{border-color:#f2a7a7}.absolute-voice-provider-contracts__row p{margin:10px 0}.absolute-voice-provider-contracts__remediations{display:grid;gap:8px;list-style:none;margin:0 0 10px;padding:0}.absolute-voice-provider-contracts__remediations li{background:#fff7ed;border:1px solid #fed7aa;border-radius:12px;display:grid;gap:3px;padding:8px}.absolute-voice-provider-contracts__remediations a,.absolute-voice-provider-contracts__remediations strong{color:#9a3412}.absolute-voice-provider-contracts__remediations span{color:#7c2d12}.absolute-voice-provider-contracts__row dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-contracts__row div{background:#f7fff9;border:1px solid #d6eadb;border-radius:12px;padding:8px}.absolute-voice-provider-contracts__row dt{font-size:12px}.absolute-voice-provider-contracts__row dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-contracts__error{color:#9f1239;font-weight:700}`;
@@ -3110,7 +3302,7 @@ var createVoiceProviderStatusStore = (path = "/api/provider-status", options = {
3110
3302
  // src/client/providerStatusWidget.ts
3111
3303
  var DEFAULT_TITLE9 = "Voice Providers";
3112
3304
  var DEFAULT_DESCRIPTION9 = "Live provider health, fallback counts, latency, and suppression state from your self-hosted trace store.";
3113
- var escapeHtml10 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3305
+ var escapeHtml11 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3114
3306
  var formatProvider3 = (provider) => provider.split(/[-_\s]+/).filter(Boolean).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ") || provider;
3115
3307
  var formatStatus4 = (status) => status.split("-").map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
3116
3308
  var formatLatency = (value) => typeof value === "number" ? `${value}ms` : "No samples";
@@ -3166,25 +3358,25 @@ var createVoiceProviderStatusViewModel = (snapshot, options = {}) => {
3166
3358
  };
3167
3359
  var renderVoiceProviderStatusHTML = (snapshot, options = {}) => {
3168
3360
  const model = createVoiceProviderStatusViewModel(snapshot, options);
3169
- const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml10(provider.status)}">
3361
+ const providers = model.providers.length ? `<div class="absolute-voice-provider-status__providers">${model.providers.map((provider) => `<article class="absolute-voice-provider-status__provider absolute-voice-provider-status__provider--${escapeHtml11(provider.status)}">
3170
3362
  <header>
3171
- <strong>${escapeHtml10(provider.label)}</strong>
3172
- <span>${escapeHtml10(formatStatus4(provider.status))}</span>
3363
+ <strong>${escapeHtml11(provider.label)}</strong>
3364
+ <span>${escapeHtml11(formatStatus4(provider.status))}</span>
3173
3365
  </header>
3174
- <p>${escapeHtml10(provider.detail)}</p>
3366
+ <p>${escapeHtml11(provider.detail)}</p>
3175
3367
  <dl>${provider.rows.map((row) => `<div>
3176
- <dt>${escapeHtml10(row.label)}</dt>
3177
- <dd>${escapeHtml10(row.value)}</dd>
3368
+ <dt>${escapeHtml11(row.label)}</dt>
3369
+ <dd>${escapeHtml11(row.value)}</dd>
3178
3370
  </div>`).join("")}</dl>
3179
3371
  </article>`).join("")}</div>` : '<p class="absolute-voice-provider-status__empty">Run voice traffic to see provider health.</p>';
3180
- return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml10(model.status)}">
3372
+ return `<section class="absolute-voice-provider-status absolute-voice-provider-status--${escapeHtml11(model.status)}">
3181
3373
  <header class="absolute-voice-provider-status__header">
3182
- <span class="absolute-voice-provider-status__eyebrow">${escapeHtml10(model.title)}</span>
3183
- <strong class="absolute-voice-provider-status__label">${escapeHtml10(model.label)}</strong>
3374
+ <span class="absolute-voice-provider-status__eyebrow">${escapeHtml11(model.title)}</span>
3375
+ <strong class="absolute-voice-provider-status__label">${escapeHtml11(model.label)}</strong>
3184
3376
  </header>
3185
- <p class="absolute-voice-provider-status__description">${escapeHtml10(model.description)}</p>
3377
+ <p class="absolute-voice-provider-status__description">${escapeHtml11(model.description)}</p>
3186
3378
  ${providers}
3187
- ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml10(model.error)}</p>` : ""}
3379
+ ${model.error ? `<p class="absolute-voice-provider-status__error">${escapeHtml11(model.error)}</p>` : ""}
3188
3380
  </section>`;
3189
3381
  };
3190
3382
  var getVoiceProviderStatusCSS = () => `.absolute-voice-provider-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-provider-status--error,.absolute-voice-provider-status--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-provider-status__header,.absolute-voice-provider-status__provider header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-provider-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-provider-status__label{font-size:24px;line-height:1}.absolute-voice-provider-status__description,.absolute-voice-provider-status__provider p,.absolute-voice-provider-status__provider dt,.absolute-voice-provider-status__empty{color:#514733}.absolute-voice-provider-status__providers{display:grid;gap:12px;margin-top:14px}.absolute-voice-provider-status__provider{background:#fff;border:1px solid #eee4d2;border-radius:16px;padding:14px}.absolute-voice-provider-status__provider--degraded,.absolute-voice-provider-status__provider--rate-limited,.absolute-voice-provider-status__provider--suppressed{border-color:#f2a7a7}.absolute-voice-provider-status__provider--recoverable{border-color:#fbbf24}.absolute-voice-provider-status__provider p{margin:10px 0}.absolute-voice-provider-status__provider dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-provider-status__provider div{background:#fffaf0;border:1px solid #eee4d2;border-radius:12px;padding:8px}.absolute-voice-provider-status__provider dt{font-size:12px}.absolute-voice-provider-status__provider dd{font-weight:800;margin:4px 0 0}.absolute-voice-provider-status__empty{margin:14px 0 0}.absolute-voice-provider-status__error{color:#9f1239;font-weight:700}`;
@@ -3413,7 +3605,7 @@ var createVoiceRoutingStatusStore = (path = "/api/routing/latest", options = {})
3413
3605
  // src/client/routingStatusWidget.ts
3414
3606
  var DEFAULT_TITLE10 = "Voice Routing";
3415
3607
  var DEFAULT_DESCRIPTION10 = "Latest provider routing decision from the self-hosted trace store.";
3416
- var escapeHtml11 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3608
+ var escapeHtml12 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3417
3609
  var formatValue = (value, fallback = "None") => typeof value === "string" && value.trim() ? value : typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
3418
3610
  var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
3419
3611
  const decision = snapshot.decision;
@@ -3450,17 +3642,17 @@ var createVoiceRoutingStatusViewModel = (snapshot, options = {}) => {
3450
3642
  var renderVoiceRoutingStatusHTML = (snapshot, options = {}) => {
3451
3643
  const model = createVoiceRoutingStatusViewModel(snapshot, options);
3452
3644
  const rows = model.rows.length ? `<div class="absolute-voice-routing-status__grid">${model.rows.map((row) => `<div>
3453
- <span>${escapeHtml11(row.label)}</span>
3454
- <strong>${escapeHtml11(row.value)}</strong>
3645
+ <span>${escapeHtml12(row.label)}</span>
3646
+ <strong>${escapeHtml12(row.value)}</strong>
3455
3647
  </div>`).join("")}</div>` : '<p class="absolute-voice-routing-status__empty">Start a voice session to see the selected provider.</p>';
3456
- return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml11(model.status)}">
3648
+ return `<section class="absolute-voice-routing-status absolute-voice-routing-status--${escapeHtml12(model.status)}">
3457
3649
  <header class="absolute-voice-routing-status__header">
3458
- <span class="absolute-voice-routing-status__eyebrow">${escapeHtml11(model.title)}</span>
3459
- <strong class="absolute-voice-routing-status__label">${escapeHtml11(model.label)}</strong>
3650
+ <span class="absolute-voice-routing-status__eyebrow">${escapeHtml12(model.title)}</span>
3651
+ <strong class="absolute-voice-routing-status__label">${escapeHtml12(model.label)}</strong>
3460
3652
  </header>
3461
- <p class="absolute-voice-routing-status__description">${escapeHtml11(model.description)}</p>
3653
+ <p class="absolute-voice-routing-status__description">${escapeHtml12(model.description)}</p>
3462
3654
  ${rows}
3463
- ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml11(model.error)}</p>` : ""}
3655
+ ${model.error ? `<p class="absolute-voice-routing-status__error">${escapeHtml12(model.error)}</p>` : ""}
3464
3656
  </section>`;
3465
3657
  };
3466
3658
  var getVoiceRoutingStatusCSS = () => `.absolute-voice-routing-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-routing-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-routing-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-routing-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-routing-status__label{font-size:24px;line-height:1}.absolute-voice-routing-status__description{color:#514733;margin:12px 0 0}.absolute-voice-routing-status__grid{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin-top:14px}.absolute-voice-routing-status__grid div{background:#fff;border:1px solid #eee4d2;border-radius:14px;padding:10px 12px}.absolute-voice-routing-status__grid span{color:#655944;display:block;font-size:12px;margin-bottom:4px}.absolute-voice-routing-status__grid strong{overflow-wrap:anywhere}.absolute-voice-routing-status__empty{color:#655944;margin:14px 0 0}.absolute-voice-routing-status__error{color:#9f1239;font-weight:700}`;
@@ -3891,7 +4083,7 @@ var createVoiceTurnLatencyStore = (path = "/api/turn-latency", options = {}) =>
3891
4083
  var DEFAULT_TITLE11 = "Turn Latency";
3892
4084
  var DEFAULT_DESCRIPTION11 = "Per-turn timing from first transcript to commit and assistant response start.";
3893
4085
  var DEFAULT_PROOF_LABEL = "Run latency proof";
3894
- var escapeHtml12 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
4086
+ var escapeHtml13 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
3895
4087
  var formatMs2 = (value) => typeof value === "number" ? `${Math.round(value)}ms` : "n/a";
3896
4088
  var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
3897
4089
  const turns = (snapshot.report?.turns ?? []).map((turn) => ({
@@ -3919,25 +4111,25 @@ var createVoiceTurnLatencyViewModel = (snapshot, options = {}) => {
3919
4111
  };
3920
4112
  var renderVoiceTurnLatencyHTML = (snapshot, options = {}) => {
3921
4113
  const model = createVoiceTurnLatencyViewModel(snapshot, options);
3922
- const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml12(turn.status)}">
4114
+ const turns = model.turns.length ? `<div class="absolute-voice-turn-latency__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-latency__turn absolute-voice-turn-latency__turn--${escapeHtml13(turn.status)}">
3923
4115
  <header>
3924
- <strong>${escapeHtml12(turn.label)}</strong>
3925
- <span>${escapeHtml12(turn.status)}</span>
4116
+ <strong>${escapeHtml13(turn.label)}</strong>
4117
+ <span>${escapeHtml13(turn.status)}</span>
3926
4118
  </header>
3927
4119
  <dl>${turn.rows.map((row) => `<div>
3928
- <dt>${escapeHtml12(row.label)}</dt>
3929
- <dd>${escapeHtml12(row.value)}</dd>
4120
+ <dt>${escapeHtml13(row.label)}</dt>
4121
+ <dd>${escapeHtml13(row.value)}</dd>
3930
4122
  </div>`).join("")}</dl>
3931
4123
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-latency__empty">Complete a voice turn to see latency diagnostics.</p>';
3932
- return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml12(model.status)}">
4124
+ return `<section class="absolute-voice-turn-latency absolute-voice-turn-latency--${escapeHtml13(model.status)}">
3933
4125
  <header class="absolute-voice-turn-latency__header">
3934
- <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml12(model.title)}</span>
3935
- <strong class="absolute-voice-turn-latency__label">${escapeHtml12(model.label)}</strong>
4126
+ <span class="absolute-voice-turn-latency__eyebrow">${escapeHtml13(model.title)}</span>
4127
+ <strong class="absolute-voice-turn-latency__label">${escapeHtml13(model.label)}</strong>
3936
4128
  </header>
3937
- <p class="absolute-voice-turn-latency__description">${escapeHtml12(model.description)}</p>
3938
- ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml12(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
4129
+ <p class="absolute-voice-turn-latency__description">${escapeHtml13(model.description)}</p>
4130
+ ${model.showProofAction ? `<button class="absolute-voice-turn-latency__proof" data-absolute-voice-turn-latency-proof type="button">${escapeHtml13(model.proofLabel ?? DEFAULT_PROOF_LABEL)}</button>` : ""}
3939
4131
  ${turns}
3940
- ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml12(model.error)}</p>` : ""}
4132
+ ${model.error ? `<p class="absolute-voice-turn-latency__error">${escapeHtml13(model.error)}</p>` : ""}
3941
4133
  </section>`;
3942
4134
  };
3943
4135
  var mountVoiceTurnLatency = (element, path = "/api/turn-latency", options = {}) => {
@@ -4170,7 +4362,7 @@ var createVoiceTurnQualityStore = (path = "/api/turn-quality", options = {}) =>
4170
4362
  // src/client/turnQualityWidget.ts
4171
4363
  var DEFAULT_TITLE12 = "Turn Quality";
4172
4364
  var DEFAULT_DESCRIPTION12 = "Per-turn STT confidence, fallback selection, corrections, and transcript coverage.";
4173
- var escapeHtml13 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
4365
+ var escapeHtml14 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
4174
4366
  var formatConfidence = (value) => typeof value === "number" ? `${Math.round(value * 100)}%` : "n/a";
4175
4367
  var formatMaybe = (value) => value === undefined || value === "" ? "n/a" : String(value);
4176
4368
  var getTurnDetail = (turn) => {
@@ -4220,25 +4412,25 @@ var createVoiceTurnQualityViewModel = (snapshot, options = {}) => {
4220
4412
  };
4221
4413
  var renderVoiceTurnQualityHTML = (snapshot, options = {}) => {
4222
4414
  const model = createVoiceTurnQualityViewModel(snapshot, options);
4223
- const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml13(turn.status)}">
4415
+ const turns = model.turns.length ? `<div class="absolute-voice-turn-quality__turns">${model.turns.map((turn) => `<article class="absolute-voice-turn-quality__turn absolute-voice-turn-quality__turn--${escapeHtml14(turn.status)}">
4224
4416
  <header>
4225
- <strong>${escapeHtml13(turn.label)}</strong>
4226
- <span>${escapeHtml13(turn.status)}</span>
4417
+ <strong>${escapeHtml14(turn.label)}</strong>
4418
+ <span>${escapeHtml14(turn.status)}</span>
4227
4419
  </header>
4228
- <p>${escapeHtml13(turn.detail)}</p>
4420
+ <p>${escapeHtml14(turn.detail)}</p>
4229
4421
  <dl>${turn.rows.map((row) => `<div>
4230
- <dt>${escapeHtml13(row.label)}</dt>
4231
- <dd>${escapeHtml13(row.value)}</dd>
4422
+ <dt>${escapeHtml14(row.label)}</dt>
4423
+ <dd>${escapeHtml14(row.value)}</dd>
4232
4424
  </div>`).join("")}</dl>
4233
4425
  </article>`).join("")}</div>` : '<p class="absolute-voice-turn-quality__empty">Complete a voice turn to see STT quality diagnostics.</p>';
4234
- return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml13(model.status)}">
4426
+ return `<section class="absolute-voice-turn-quality absolute-voice-turn-quality--${escapeHtml14(model.status)}">
4235
4427
  <header class="absolute-voice-turn-quality__header">
4236
- <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml13(model.title)}</span>
4237
- <strong class="absolute-voice-turn-quality__label">${escapeHtml13(model.label)}</strong>
4428
+ <span class="absolute-voice-turn-quality__eyebrow">${escapeHtml14(model.title)}</span>
4429
+ <strong class="absolute-voice-turn-quality__label">${escapeHtml14(model.label)}</strong>
4238
4430
  </header>
4239
- <p class="absolute-voice-turn-quality__description">${escapeHtml13(model.description)}</p>
4431
+ <p class="absolute-voice-turn-quality__description">${escapeHtml14(model.description)}</p>
4240
4432
  ${turns}
4241
- ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml13(model.error)}</p>` : ""}
4433
+ ${model.error ? `<p class="absolute-voice-turn-quality__error">${escapeHtml14(model.error)}</p>` : ""}
4242
4434
  </section>`;
4243
4435
  };
4244
4436
  var getVoiceTurnQualityCSS = () => `.absolute-voice-turn-quality{border:1px solid #e4d1a3;border-radius:20px;background:#fff9eb;color:#17120a;padding:18px;box-shadow:0 18px 40px rgba(73,48,14,.12);font-family:inherit}.absolute-voice-turn-quality--error,.absolute-voice-turn-quality--warning{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-turn-quality__header,.absolute-voice-turn-quality__turn header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-turn-quality__eyebrow{color:#8a5a0a;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-turn-quality__label{font-size:24px;line-height:1}.absolute-voice-turn-quality__description,.absolute-voice-turn-quality__turn p,.absolute-voice-turn-quality__turn dt,.absolute-voice-turn-quality__empty{color:#5a4930}.absolute-voice-turn-quality__turns{display:grid;gap:12px;margin-top:14px}.absolute-voice-turn-quality__turn{background:#fff;border:1px solid #f0dfba;border-radius:16px;padding:14px}.absolute-voice-turn-quality__turn--pass{border-color:#86efac}.absolute-voice-turn-quality__turn--warn,.absolute-voice-turn-quality__turn--unknown{border-color:#fbbf24}.absolute-voice-turn-quality__turn--fail{border-color:#f2a7a7}.absolute-voice-turn-quality__turn p{margin:10px 0}.absolute-voice-turn-quality__turn dl{display:grid;gap:8px;grid-template-columns:repeat(2,minmax(0,1fr));margin:0}.absolute-voice-turn-quality__turn div{background:#fff9eb;border:1px solid #f0dfba;border-radius:12px;padding:8px}.absolute-voice-turn-quality__turn dt{font-size:12px}.absolute-voice-turn-quality__turn dd{font-weight:800;margin:4px 0 0}.absolute-voice-turn-quality__empty{margin:14px 0 0}.absolute-voice-turn-quality__error{color:#9f1239;font-weight:700}`;