diff --git a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py
index 6fdccab..b6f22af 100644
--- a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py
+++ b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni_webpage_generator.py
@@ -568,6 +568,7 @@ class FlomniWebpageGenerator(WebpageGeneratorBase):
"Exposure time": _gvar(g, "tomo_countingtime", ".3f", " s"),
"Angle step": _gvar(g, "tomo_angle_stepsize", ".2f", "\u00b0"),
"Stitch x / y": f"{_fmt2(stx)} / {_fmt2(sty)} \u00b5m",
+ "Corridor size": str(g.get_global_var("corridor_size") or "N/A"),
}
return {
@@ -768,7 +769,7 @@ def _render_html(phone_numbers: list) -> str:
.theme-btn:hover {{ background: var(--border); color: var(--text); }}
.theme-btn.active {{
background: var(--status-color); border-color: var(--status-color);
- color: var(--bg);
+ color: #1a1d2e;
}}
/* ── Cards ── */
@@ -792,7 +793,7 @@ def _render_html(phone_numbers: list) -> str:
.status-pill {{
font-family: var(--mono); font-size: 0.75rem; font-weight: 700;
letter-spacing: 0.12em; text-transform: uppercase;
- color: var(--bg); background: var(--status-color);
+ color: #1a1d2e; background: var(--status-color);
padding: 0.35rem 1rem; border-radius: 100px;
white-space: nowrap; transition: background 0.6s; flex-shrink: 0;
}}
@@ -898,6 +899,7 @@ def _render_html(phone_numbers: list) -> str:
transition: background 0.3s; flex-shrink: 0;
}}
.audio-dot.active {{ background: var(--c-scanning); box-shadow: 0 0 6px var(--c-scanning); }}
+ .audio-dot.confirmed {{ background: var(--c-idle-short); }}
.audio-text {{ font-size: 0.85rem; color: var(--text-dim); }}
.audio-controls {{ display: flex; gap: 0.6rem; flex-wrap: wrap; }}
@@ -910,7 +912,7 @@ def _render_html(phone_numbers: list) -> str:
min-height: 44px;
}}
button:hover {{ background: var(--border); }}
- button.active {{ background: var(--status-color); border-color: var(--status-color); color: var(--bg); }}
+ button.active {{ background: var(--status-color); border-color: var(--status-color); color: #1a1d2e; }}
button.confirm-btn {{
background: color-mix(in srgb, var(--c-idle-long) 20%, var(--surface2));
border-color: var(--c-idle-long); color: var(--c-idle-long); display: none;
@@ -1108,8 +1110,13 @@ function toggleAudio(){{
updateAudioUI(); if(!audioEnabled) stopWarning();
}}
function confirmWarning(){{
- warningConfirmed=true; stopWarning();
+ warningConfirmed=true;
+ stopWarning();
+ // hide button, dim LED — audio stops but visual warning remains
document.getElementById('btn-confirm').style.display='none';
+ const dot=document.getElementById('audio-dot');
+ dot.classList.remove('active');
+ dot.classList.add('confirmed');
}}
function updateAudioUI(){{
const btn=document.getElementById('btn-toggle'),
@@ -1117,17 +1124,24 @@ function updateAudioUI(){{
txt=document.getElementById('audio-text');
if(audioEnabled){{
btn.textContent='Disable'; btn.classList.add('active');
- dot.classList.add('active'); txt.textContent='Audio warnings: enabled';
+ if(!warningConfirmed) dot.classList.add('active');
+ txt.textContent='Audio warnings: enabled';
}}else{{
btn.textContent='Enable'; btn.classList.remove('active');
- dot.classList.remove('active'); txt.textContent='Audio warnings: disabled';
+ dot.classList.remove('active');
+ txt.textContent='Audio warnings: disabled';
}}
}}
function startWarning(){{
- if(warningTimer) return;
- if(audioEnabled&&!warningConfirmed) warningChime();
- warningTimer=setInterval(()=>{{if(audioEnabled&&!warningConfirmed) warningChime();}},30000);
- document.getElementById('btn-confirm').style.display='inline-block';
+ // Start the audio timer only if not already running and not confirmed
+ if(!warningTimer && !warningConfirmed){{
+ if(audioEnabled) warningChime();
+ warningTimer=setInterval(()=>{{if(audioEnabled&&!warningConfirmed) warningChime();}},30000);
+ }}
+ // Show confirm button only if warning not yet acknowledged this episode
+ if(!warningConfirmed){{
+ document.getElementById('btn-confirm').style.display='inline-block';
+ }}
}}
function stopWarning(){{ if(warningTimer){{clearInterval(warningTimer);warningTimer=null;}} }}
@@ -1136,7 +1150,7 @@ const LABELS={{scanning:'SCANNING',running:'RUNNING',idle_short:'IDLE',idle_long
const DETAILS={{
scanning: d=>'Tomo scan in progress · projection '+(d.progress.projection||0)+' of '+(d.progress.total_projections||0)+' · '+(d.progress.tomo_type||''),
running: d=>'Queue active · outside tomo heartbeat window',
- idle_short:d=>'Finished normally · idle for '+d.idle_for_human+'',
+ idle_short:d=>'Idle for '+d.idle_for_human+'',
idle_long: d=>'Idle for '+d.idle_for_human+' — no tomo scan running',
error: d=>'Queue stopped unexpectedly · idle for '+(d.idle_for_human||'?')+'',
unknown: d=>'Status unknown · waiting for first data…',
@@ -1170,7 +1184,13 @@ function renderInstrument(setup){{
function render(d){{
const s=d.experiment_status||'unknown',p=d.progress||{{}};
- if(lastWarnStatus!==null&&WARN_STATUSES.has(lastWarnStatus)&&!WARN_STATUSES.has(s)) warningConfirmed=false;
+ if(lastWarnStatus!==null&&WARN_STATUSES.has(lastWarnStatus)&&!WARN_STATUSES.has(s)){{
+ // Status recovered from warning — re-arm for next idle episode
+ warningConfirmed=false;
+ const dot=document.getElementById('audio-dot');
+ dot.classList.remove('confirmed');
+ if(audioEnabled) dot.classList.add('active');
+ }}
lastWarnStatus=s;
document.body.className=s;
document.getElementById('status-pill').textContent=LABELS[s]||s.toUpperCase();