"""Standalone official-LVGL status frontend for the headless gateway.

This file is intentionally MicroPython compatible.  It imports no LabCobot
CPython modules and reads only the secret-free, loopback-only MJPEG health
endpoint.  The production service runs it with the Unix build from LVGL's
official ``lvgl/lv_micropython`` repository.
"""

try:
    import ujson as json
except ImportError:  # CPython tests and some MicroPython Unix builds.
    import json

try:
    import hashlib
except ImportError:  # Older MicroPython builds expose the module as uhashlib.
    import uhashlib as hashlib

import os
import time

DEFAULT_HEALTH_URL = "http://127.0.0.1:8765/healthz"
DEFAULT_POLL_MS = 5000
DEFAULT_TIMEOUT_MS = 1000
DEFAULT_WIDTH = 1024
DEFAULT_HEIGHT = 600
DEFAULT_ZOOM = 1
DEFAULT_SCREENSAVER_TIMEOUT_SECONDS = 300
MIN_SCREENSAVER_TIMEOUT_SECONDS = 30
MAX_SCREENSAVER_TIMEOUT_SECONDS = 86400
SCREENSAVER_CHECK_MS = 250
COMPLETION_CHECK_MS = 20
SCREENSAVER_REVEAL_DIAGNOSTIC_SCHEMA_VERSION = 1
MAX_SCREENSAVER_REVEAL_COUNT = 2147483647
INPUT_ACTIVITY_DIAGNOSTIC_SCHEMA_VERSION = 1
MAX_INPUT_ACTIVITY_COUNT = 2147483647
MAX_INPUT_ACTIVITY_AGE_MS = 2147483647
MAX_RESPONSE_BYTES = 65536
MAX_HEADER_BYTES = 16384
MAX_SNAPSHOT_BYTES = 512 * 1024
DEFAULT_RUNTIME_DIR = "/run/labcobot-lvgl"
DEFAULT_TRANSPORT_DIR = "/run/labcobot-lvgl-ipc"
TRANSPORT_BROKER_SCHEMA = "labcobot.lvgl.transport.broker.v1"
TRANSPORT_REQUEST_SCHEMA = "labcobot.lvgl.transport.request.v1"
TRANSPORT_RESULT_SCHEMA = "labcobot.lvgl.transport.result.v1"
MAX_TRANSPORT_STATUS_BYTES = 1024
MAX_TRANSPORT_REQUEST_BYTES = 4096
MAX_TRANSPORT_RESULT_BYTES = MAX_RESPONSE_BYTES + 4096
MAX_TRANSPORT_GENERATION = 2147483647
_LOOPBACK_HOSTS = ("127.0.0.1", "localhost", "::1")
OTA_CHECK_PATH = "/api/ota/check"
OTA_ACTION_HEADER = "signed-ota-check"
CAPTURE_START_PATH = "/api/capture-run/start"
CAPTURE_STOP_PATH = "/api/capture-run/stop"
CAPTURE_START_ACTION_HEADER = "capture-run-start"
CAPTURE_STOP_ACTION_HEADER = "capture-run-stop"
SOFTWARE_STOP_PATH = "/api/safety/stop"
SOFTWARE_STOP_ACTION_HEADER = "software-stop-all-v1"
MOTION_SEARCH_ARM_PATH = "/api/motion/search/arm"
MOTION_SEARCH_ARM_ACTION_HEADER = "dynamic-valve-search-arm-v1"
SAFETY_CONFIGURE_PATH = "/api/safety/configure"
SAFETY_CONFIGURE_ACTION_HEADER = "lite6-safety-boundary-configure-v1"
PETRI_START_PATH = "/api/petri/start"
PETRI_START_ACTION_HEADER = "commissioned-petri-start-v1"
REGISTRATION_VERIFY_PATH = "/api/registration/verify"
REGISTRATION_VERIFY_ACTION_HEADER = "device-registration-verify-v1"
RECOVERY_START_PATH = "/api/recovery/home"
RECOVERY_START_ACTION_HEADER = "reviewed-recovery-home-v1"
MANUAL_REVIEW_PATH = "/api/petri/review"
MANUAL_REVIEW_ACTION_HEADER = "petri-review-select-v1"
MANUAL_REVIEW_PREVIEW_PATH = "/api/petri/review.jpg"
WORKSPACE_TEACH_START_PATH = "/api/workspace-teach/start"
WORKSPACE_TEACH_CAPTURE_PATH = "/api/workspace-teach/capture"
WORKSPACE_TEACH_CANCEL_PATH = "/api/workspace-teach/cancel"
WORKSPACE_TEACH_FINALIZE_PATH = "/api/workspace-teach/finalize"
WORKSPACE_TEACH_START_ACTION_HEADER = "workspace-teach-start-v1"
WORKSPACE_TEACH_CAPTURE_ACTION_HEADER = "workspace-teach-capture-v1"
WORKSPACE_TEACH_CANCEL_ACTION_HEADER = "workspace-teach-cancel-v1"
WORKSPACE_TEACH_FINALIZE_ACTION_HEADER = "workspace-teach-finalize-v1"
TENANT_LOGIN_PATH = "/api/tenant-auth/login"
TENANT_LOGOUT_PATH = "/api/tenant-auth/logout"
TENANT_LOGIN_ACTION_HEADER = "tenant-mobile-login-v1"
TENANT_LOGOUT_ACTION_HEADER = "tenant-mobile-logout-v1"
SNAPSHOT_CLIENT_HEADER = "lvgl-frontend-v1"
_GENERAL_WORK_KEYS = (
    "health",
    "preview",
    "motion-search",
    "safety-configure",
    "capture",
    "update",
    "operations",
    "workspace-teach",
    "tenant-auth",
    "hand-training",
)
_STOP_WORK_KEYS = ("software-stop",)
_ALL_WORK_KEYS = _GENERAL_WORK_KEYS + _STOP_WORK_KEYS
REBUILD_STATE_SCHEMA_VERSION = 1
MAX_RETIRED_LAYOUTS = 2
_REBUILD_ACTIVE_VIEWS = (
    "home",
    "tool",
    "workspace",
    "system",
    "robot_metrics",
    "safety_config",
    "capture",
    "updates",
    "metrics",
    "operations",
    "production",
    "manual_review",
    "digital_twin",
    "workspace_teach",
    "tenant_auth",
    "hand_training",
)
_REBUILD_PENDING_FIELDS = (
    "_update_request_pending",
    "_capture_request_pending",
    "_motion_search_request_pending",
    "_safety_configuration_request_pending",
    "_safety_configuration_local_pending",
    "_operations_request_pending",
    "_workspace_teach_request_pending",
    "_tenant_auth_request_pending",
    "_hand_training_request_pending",
    "_software_stop_request_pending",
)
_REBUILD_CHALLENGE_FIELDS = (
    "_capture_start_challenge",
    "_motion_search_challenge",
    "_safety_configuration_challenge",
    "_petri_start_challenge",
    "_recovery_start_challenge",
    "_manual_review_challenge",
)
_REBUILD_VIEW_FIELDS = (
    "_last_view",
    "_last_ota_view",
    "_last_capture_view",
    "_last_motion_search_view",
    "_last_safety_configuration_view",
    "_last_digital_twin_view",
    "_last_workspace_teach_view",
    "_last_tenant_auth_view",
    "_last_operations_view",
)
_OPERATION_KEYS = {
    "health": "health",
    "snapshot_tool": "preview",
    "snapshot_workspace": "preview",
    "motion_search_arm": "motion-search",
    "safety_configure": "safety-configure",
    "capture_start": "capture",
    "capture_stop": "capture",
    "ota_check": "update",
    "petri_start": "operations",
    "recovery_home": "operations",
    "registration_verify": "operations",
    "manual_review": "operations",
    "manual_review_preview": "operations",
    "workspace_teach_start": "workspace-teach",
    "workspace_teach_capture": "workspace-teach",
    "workspace_teach_cancel": "workspace-teach",
    "workspace_teach_finalize": "workspace-teach",
    "tenant_login": "tenant-auth",
    "tenant_logout": "tenant-auth",
    "hand_training_start": "hand-training",
    "hand_training_tool": "hand-training",
    "hand_training_end": "hand-training",
    "software_stop": "software-stop",
}
_CHALLENGE_OPERATIONS = (
    "capture_start",
    "motion_search_arm",
    "safety_configure",
    "petri_start",
    "recovery_home",
    "manual_review",
    "workspace_teach_finalize",
)
_CREDENTIAL_OPERATIONS = ("tenant_login",)
_BOOLEAN_OPERATIONS = ("hand_training_tool",)
_TRANSPORT_OUTCOMES = (
    "completed",
    "timeout",
    "busy",
    "indeterminate",
    "invalid",
    "unavailable",
)
_TRANSPORT_ERRORS = (
    "",
    "timeout",
    "busy",
    "indeterminate",
    "invalid_request",
    "invalid_response",
    "unavailable",
)


def _lower_hex_exact(value, length):
    return bool(
        isinstance(value, str)
        and len(value) == length
        and all(character in "0123456789abcdef" for character in value)
    )


def _random_epoch():
    raw = os.urandom(16)
    return "".join("%02x" % value for value in raw)


def _transport_request(operation, payload=None):
    """Build the only request descriptor accepted by the local broker."""

    if operation not in _OPERATION_KEYS:
        raise ValueError("transport operation is not allowlisted")
    value = {} if payload is None else payload
    if not isinstance(value, dict):
        raise ValueError("transport payload must be an object")
    if not value:
        value = {}
    elif operation in _CREDENTIAL_OPERATIONS:
        if set(value) != {"tenant_url", "username", "password"}:
            raise ValueError("transport credential payload is invalid")
    elif operation in _BOOLEAN_OPERATIONS:
        if set(value) != {"active"} or type(value.get("active")) is not bool:
            raise ValueError("transport boolean payload is invalid")
        if (
            not isinstance(value.get("tenant_url"), str)
            or not 1 <= len(value["tenant_url"]) <= 512
            or not isinstance(value.get("username"), str)
            or not 1 <= len(value["username"]) <= 254
            or not isinstance(value.get("password"), str)
            or not 1 <= len(value["password"]) <= 128
        ):
            raise ValueError("transport credential payload is invalid")
    elif (
        operation not in _CHALLENGE_OPERATIONS
        or set(value) != {"challenge"}
        or not _lower_hex_exact(value.get("challenge"), 32)
    ):
        raise ValueError("transport payload is invalid")
    return {"operation": operation, "payload": value}


def _valid_transport_request_spec(value, key=None):
    if not isinstance(value, dict) or set(value) != {"operation", "payload"}:
        return False
    operation = value.get("operation")
    try:
        normalized = _transport_request(operation, value.get("payload"))
    except (TypeError, ValueError):
        return False
    return normalized == value and (key is None or _OPERATION_KEYS[operation] == key)


def _read_file_bounded(path, maximum):
    metadata = os.stat(path)
    # The mailbox lives on a POSIX /run filesystem.  Refuse FIFOs, devices,
    # sockets, and directories before opening so a corrupt fixed slot cannot
    # turn the LVGL completion timer into a blocking read.
    if (metadata[0] & 0xF000) != 0x8000:
        raise ValueError("transport path is not a regular file")
    if len(metadata) > 6 and metadata[6] > maximum:
        raise ValueError("transport file exceeds byte limit")
    with open(path, "rb") as stream:
        payload = stream.read(maximum + 1)
    if len(payload) > maximum:
        raise ValueError("transport file exceeds byte limit")
    return payload


def _decode_json_object(raw):
    try:
        value = json.loads(raw.decode("utf-8"))
    except (AttributeError, TypeError, UnicodeError, ValueError):
        raise ValueError("transport JSON is invalid")
    if not isinstance(value, dict):
        raise ValueError("transport JSON must be an object")
    return value


def _sha256_hex(payload):
    hasher = hashlib.sha256()
    hasher.update(payload)
    digest = hasher.digest()
    return "".join("%02x" % value for value in digest)


class _BrokerMailbox:
    """Bounded file IPC with no MicroPython threads or network calls.

    The companion CPython broker owns HTTP and subprocess work.  This object
    only commits small fixed request descriptors and polls fixed result files.
    Result callbacks are retained in memory and invoked exclusively by
    :meth:`drain`, which is called from an LVGL timer on the UI thread.
    """

    def __init__(self, runtime_dir=DEFAULT_TRANSPORT_DIR, frontend_epoch=None):
        root = str(runtime_dir or "").rstrip("/")
        if not root.startswith("/") or root == "":
            raise ValueError("transport runtime directory must be absolute")
        epoch = frontend_epoch or _random_epoch()
        if not _lower_hex_exact(epoch, 32):
            raise ValueError("frontend epoch is invalid")
        self.runtime_dir = root
        self.request_dir = root + "/requests"
        self.result_dir = root + "/results"
        self.blob_dir = root + "/blobs"
        self.status_path = root + "/broker.json"
        self.frontend_epoch = epoch
        self.broker_epoch = ""
        self._generations = dict((key, 0) for key in _ALL_WORK_KEYS)
        self._pending = {}
        self._closed = False
        self.broker_epoch = self._read_broker_epoch()

    def _read_broker_epoch(self):
        try:
            status = _decode_json_object(
                _read_file_bounded(self.status_path, MAX_TRANSPORT_STATUS_BYTES)
            )
        except (OSError, ValueError):
            return ""
        if (
            set(status) != {"schema", "broker_epoch"}
            or status.get("schema") != TRANSPORT_BROKER_SCHEMA
            or not _lower_hex_exact(status.get("broker_epoch"), 32)
        ):
            return ""
        return status["broker_epoch"]

    def _next_generation(self, key):
        generation = self._generations[key] + 1
        if generation > MAX_TRANSPORT_GENERATION:
            if self._pending:
                return 0
            self.frontend_epoch = _random_epoch()
            self._generations = dict((name, 0) for name in _ALL_WORK_KEYS)
            generation = 1
        return generation

    def submit(self, key, request, apply, replace=False):
        """Atomically publish one request without executing transport work."""

        if key not in self._generations:
            raise ValueError("transport key is not allowlisted")
        if not _valid_transport_request_spec(request, key):
            raise ValueError("transport request descriptor is invalid")
        if not callable(apply):
            raise ValueError("transport result callback must be callable")
        if replace and key not in ("health", "preview"):
            raise ValueError("only polling requests may be coalesced")
        if self._closed:
            return False
        if key in self._pending and not replace:
            return False

        discovered_epoch = self._read_broker_epoch()
        if not discovered_epoch:
            return False
        if self.broker_epoch and discovered_epoch != self.broker_epoch:
            # Drain owns callback execution.  Refuse new work until it has
            # failed every request from the old broker epoch on the UI thread.
            if self._pending:
                return False
        self.broker_epoch = discovered_epoch
        generation = self._next_generation(key)
        if generation == 0:
            return False
        envelope = {
            "schema": TRANSPORT_REQUEST_SCHEMA,
            "broker_epoch": self.broker_epoch,
            "frontend_epoch": self.frontend_epoch,
            "key": key,
            "generation": generation,
            "operation": request["operation"],
            "payload": request["payload"],
        }
        encoded = json.dumps(envelope).encode("utf-8")
        if len(encoded) > MAX_TRANSPORT_REQUEST_BYTES:
            raise ValueError("transport request exceeds byte limit")
        temporary = self.request_dir + "/" + key + ".tmp"
        pending = self.request_dir + "/" + key + ".pending.json"
        try:
            with open(temporary, "wb") as stream:
                stream.write(encoded)
                stream.flush()
                synchronize = getattr(os, "fsync", None)
                descriptor = getattr(stream, "fileno", None)
                if callable(synchronize) and callable(descriptor):
                    synchronize(descriptor())
            os.rename(temporary, pending)
        except OSError:
            return False
        self._generations[key] = generation
        self._pending[key] = (generation, request["operation"], apply)
        return True

    def _matching_result(self, key, generation, operation):
        result_path = self.result_dir + "/" + key + ".json"
        try:
            raw = _read_file_bounded(result_path, MAX_TRANSPORT_RESULT_BYTES)
            result = _decode_json_object(raw)
        except (OSError, ValueError):
            return None
        if set(result) != {
            "schema",
            "broker_epoch",
            "frontend_epoch",
            "key",
            "generation",
            "operation",
            "outcome",
            "http_status",
            "payload",
            "transport_error",
            "blob",
        }:
            return None
        if (
            result.get("schema") != TRANSPORT_RESULT_SCHEMA
            or result.get("broker_epoch") != self.broker_epoch
            or result.get("frontend_epoch") != self.frontend_epoch
            or result.get("key") != key
            or result.get("generation") != generation
            or result.get("operation") != operation
            or result.get("outcome") not in _TRANSPORT_OUTCOMES
            or result.get("transport_error") not in _TRANSPORT_ERRORS
            or isinstance(result.get("http_status"), bool)
            or not isinstance(result.get("http_status"), int)
            or not isinstance(result.get("payload"), dict)
        ):
            return None
        outcome = result["outcome"]
        if outcome != "completed":
            expected_errors = {
                "timeout": ("timeout",),
                "busy": ("busy",),
                "indeterminate": ("indeterminate",),
                "invalid": ("invalid_request", "invalid_response"),
                "unavailable": ("unavailable",),
            }
            if (
                result["http_status"] != 0
                or result["payload"] != {}
                or result["blob"] is not None
                or result["transport_error"] not in expected_errors[outcome]
            ):
                return None
            return {
                "http_status": 0,
                "payload": {},
                "transport_error": "local request unavailable",
            }
        if not 100 <= result["http_status"] <= 599 or result["transport_error"] != "":
            return None

        blob = result["blob"]
        if blob is None:
            if operation in (
                "snapshot_tool",
                "snapshot_workspace",
                "manual_review_preview",
            ):
                return {"http_status": result["http_status"], "jpeg": b""}
            if not _valid_completed_transport_payload(
                operation,
                result["http_status"],
                result["payload"],
            ):
                return {
                    "http_status": 0,
                    "payload": {},
                    "transport_error": "local request unavailable",
                }
            return {
                "http_status": result["http_status"],
                "payload": result["payload"],
            }
        if (
            operation
            not in ("snapshot_tool", "snapshot_workspace", "manual_review_preview")
            or result["http_status"] != 200
            or result["payload"] != {}
            or not isinstance(blob, dict)
            or set(blob) != {"slot", "length", "sha256", "content_type"}
            or blob.get("slot") != key
            or isinstance(blob.get("length"), bool)
            or not isinstance(blob.get("length"), int)
            or not 4 <= blob.get("length") <= MAX_SNAPSHOT_BYTES
            or not _lower_hex_exact(blob.get("sha256"), 64)
            or blob.get("content_type") != "image/jpeg"
        ):
            return None
        try:
            jpeg = _read_file_bounded(
                self.blob_dir + "/" + key + ".bin", MAX_SNAPSHOT_BYTES
            )
            unchanged = _read_file_bounded(result_path, MAX_TRANSPORT_RESULT_BYTES)
        except (OSError, ValueError):
            return None
        if (
            unchanged != raw
            or len(jpeg) != blob["length"]
            or _sha256_hex(jpeg) != blob["sha256"]
            or not _baseline_jpeg(jpeg)
        ):
            return None
        return {"http_status": 200, "jpeg": jpeg}

    def drain(self):
        """Apply completed current-generation results on the caller thread."""

        if self._closed:
            return 0
        discovered_epoch = self._read_broker_epoch()
        if not discovered_epoch:
            return 0
        if self.broker_epoch and discovered_epoch != self.broker_epoch:
            stale = self._pending
            self._pending = {}
            self.broker_epoch = discovered_epoch
            for _key, (_generation, _operation, apply) in tuple(stale.items()):
                try:
                    apply(None, RuntimeError("transport broker restarted"))
                except Exception:
                    pass
            return len(stale)
        self.broker_epoch = discovered_epoch
        applied = 0
        for key in tuple(self._pending):
            generation, operation, apply = self._pending[key]
            response = self._matching_result(key, generation, operation)
            if response is None:
                continue
            del self._pending[key]
            try:
                apply(response, None)
            except Exception:
                pass
            applied += 1
        return applied

    def snapshot(self):
        return {
            "allowed": len(_ALL_WORK_KEYS),
            "pending": len(self._pending),
            "worker_started": False,
            "broker_ready": bool(self.broker_epoch),
        }

    def rebuild_identity(self):
        """Return the bounded immutable request identity carried over a rebuild."""

        pending = []
        for key in _ALL_WORK_KEYS:
            value = self._pending.get(key)
            if value is None:
                continue
            generation, operation, _apply = value
            pending.append((key, generation, operation))
        return (
            self.frontend_epoch,
            self.broker_epoch,
            tuple(pending),
        )

    def close(self):
        self._closed = True
        self._pending = {}


def _integer(value, name, minimum, maximum):
    try:
        parsed = int(str(value).strip())
    except (TypeError, ValueError):
        raise ValueError("%s must be an integer" % name)
    if parsed < minimum or parsed > maximum:
        raise ValueError("%s must be between %d and %d" % (name, minimum, maximum))
    return parsed


def _monotonic_ms(time_module=time):
    """Return a monotonic millisecond tick on CPython and MicroPython."""

    ticks_ms = getattr(time_module, "ticks_ms", None)
    if callable(ticks_ms):
        return int(ticks_ms())
    monotonic = getattr(time_module, "monotonic", None)
    if callable(monotonic):
        return int(monotonic() * 1000)
    return int(time_module.time() * 1000)


def _elapsed_ms(start_ms, now_ms, time_module=time):
    """Compute bounded tick elapsed time, including MicroPython tick wrap."""

    ticks_diff = getattr(time_module, "ticks_diff", None)
    if callable(ticks_diff):
        elapsed = int(ticks_diff(now_ms, start_ms))
    else:
        elapsed = int(now_ms) - int(start_ms)
    return max(0, elapsed)


def _safe_text(value, limit=80):
    """Return bounded printable ASCII for a label or diagnostic."""

    text = str(value or "")
    chars = []
    for character in text:
        codepoint = ord(character)
        chars.append(character if 32 <= codepoint <= 126 else "?")
        if len(chars) >= limit:
            break
    return "".join(chars)


def parse_health_url(url):
    """Parse the one permitted local HTTP health endpoint.

    Keeping this deliberately narrower than a general URL parser prevents a
    display configuration mistake from turning the frontend into a network
    client or leaking backend credentials through URL user-info/query values.
    """

    value = str(url or "").strip()
    prefix = "http://"
    if not value.startswith(prefix):
        raise ValueError("health URL must use loopback HTTP")
    remainder = value[len(prefix) :]
    if not remainder or "?" in remainder or "#" in remainder or "@" in remainder:
        raise ValueError("health URL must not contain credentials, query, or fragment")

    authority, separator, relative_path = remainder.partition("/")
    path = "/" + relative_path if separator else "/"
    if path != "/healthz":
        raise ValueError("health URL path must be /healthz")

    host = ""
    port_text = ""
    if authority.startswith("["):
        closing = authority.find("]")
        if closing < 0:
            raise ValueError("invalid bracketed loopback host")
        host = authority[1:closing]
        suffix = authority[closing + 1 :]
        if suffix:
            if not suffix.startswith(":"):
                raise ValueError("invalid health URL authority")
            port_text = suffix[1:]
    else:
        if authority.count(":") > 1:
            raise ValueError("IPv6 loopback must be bracketed")
        host, colon, port_text = authority.partition(":")
        if not colon:
            port_text = "80"

    host = host.lower()
    if host not in _LOOPBACK_HOSTS:
        raise ValueError("health URL host must be loopback")
    port = _integer(port_text, "health URL port", 1, 65535)
    return {
        "host": host,
        "port": port,
        "path": path,
        "url": (
            "http://[%s]:%d%s" % (host, port, path)
            if ":" in host
            else "http://%s:%d%s" % (host, port, path)
        ),
        "host_header": (
            "[%s]:%d" % (host, port) if ":" in host else "%s:%d" % (host, port)
        ),
    }


def load_config(environment=None):
    """Load and validate the small, non-secret frontend environment."""

    if environment is None:
        getter = os.getenv
    else:
        getter = environment.get

    health_url = getter("LABCOBOT_LVGL_HEALTH_URL") or DEFAULT_HEALTH_URL
    parse_health_url(health_url)
    return {
        "health_url": health_url,
        "poll_ms": _integer(
            getter("LABCOBOT_LVGL_POLL_MS") or DEFAULT_POLL_MS,
            "LABCOBOT_LVGL_POLL_MS",
            1000,
            60000,
        ),
        "timeout_ms": _integer(
            getter("LABCOBOT_LVGL_HTTP_TIMEOUT_MS") or DEFAULT_TIMEOUT_MS,
            "LABCOBOT_LVGL_HTTP_TIMEOUT_MS",
            100,
            5000,
        ),
        "width": _integer(
            getter("LABCOBOT_LVGL_WIDTH") or DEFAULT_WIDTH,
            "LABCOBOT_LVGL_WIDTH",
            640,
            3840,
        ),
        "height": _integer(
            getter("LABCOBOT_LVGL_HEIGHT") or DEFAULT_HEIGHT,
            "LABCOBOT_LVGL_HEIGHT",
            400,
            2160,
        ),
        "zoom": _integer(
            getter("LABCOBOT_LVGL_ZOOM") or DEFAULT_ZOOM,
            "LABCOBOT_LVGL_ZOOM",
            1,
            4,
        ),
        "screensaver_timeout_seconds": _integer(
            getter("LABCOBOT_LVGL_SCREENSAVER_TIMEOUT_SECONDS")
            or DEFAULT_SCREENSAVER_TIMEOUT_SECONDS,
            "LABCOBOT_LVGL_SCREENSAVER_TIMEOUT_SECONDS",
            MIN_SCREENSAVER_TIMEOUT_SECONDS,
            MAX_SCREENSAVER_TIMEOUT_SECONDS,
        ),
    }


def _baseline_jpeg_dimensions(payload):
    if not isinstance(payload, bytes):
        return None
    if len(payload) < 8 or len(payload) > MAX_SNAPSHOT_BYTES:
        return None
    if not payload.startswith(b"\xff\xd8") or not payload.endswith(b"\xff\xd9"):
        return None
    offset = 2
    dimensions = None
    jfif = False
    while offset < len(payload) - 2:
        if payload[offset] != 0xFF:
            return None
        while offset < len(payload) and payload[offset] == 0xFF:
            offset += 1
        if offset >= len(payload):
            return None
        marker = payload[offset]
        offset += 1
        if marker == 0xC2:
            return None
        if marker == 0xDA:
            return dimensions if jfif else None
        if marker in range(0xD0, 0xD8) or marker in (0x01, 0xD8):
            continue
        if offset + 2 > len(payload) - 2:
            return None
        segment_length = (payload[offset] << 8) | payload[offset + 1]
        if segment_length < 2 or offset + segment_length > len(payload) - 2:
            return None
        if marker == 0xE0 and segment_length >= 7:
            jfif = payload[offset + 2 : offset + 7] == b"JFIF\x00"
        if marker == 0xC0:
            if segment_length < 8:
                return None
            height = (payload[offset + 3] << 8) | payload[offset + 4]
            width = (payload[offset + 5] << 8) | payload[offset + 6]
            if not (1 <= width <= 4096 and 1 <= height <= 4096):
                return None
            dimensions = (width, height)
        offset += segment_length
    return None


def _baseline_jpeg(payload):
    return _baseline_jpeg_dimensions(payload) is not None


def _validate_transport_context(health_url, timeout_ms):
    # The broker reads the same secret-free environment, but validating here
    # keeps a malformed frontend configuration from publishing any work.
    parse_health_url(health_url)
    _integer(timeout_ms, "transport timeout", 100, 5000)


def fetch_health(health_url, timeout_ms=DEFAULT_TIMEOUT_MS):
    _validate_transport_context(health_url, timeout_ms)
    return _transport_request("health")


def request_update(health_url, timeout_ms=DEFAULT_TIMEOUT_MS):
    _validate_transport_context(health_url, timeout_ms)
    return _transport_request("ota_check")


def _request_capture_action(
    health_url,
    *,
    start,
    challenge=None,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    _validate_transport_context(health_url, timeout_ms)
    supplied = "" if challenge is None else challenge
    if supplied and (not start or not _lower_hex_exact(supplied, 32)):
        raise ValueError("capture challenge is invalid")
    return _transport_request(
        "capture_start" if start else "capture_stop",
        {"challenge": supplied} if supplied else {},
    )


def request_capture_start(
    health_url,
    timeout_ms=DEFAULT_TIMEOUT_MS,
    challenge=None,
):
    return _request_capture_action(
        health_url,
        start=True,
        challenge=challenge,
        timeout_ms=timeout_ms,
    )


def request_capture_stop(health_url, timeout_ms=DEFAULT_TIMEOUT_MS):
    return _request_capture_action(
        health_url,
        start=False,
        timeout_ms=timeout_ms,
    )


def request_software_stop(health_url, timeout_ms=DEFAULT_TIMEOUT_MS):
    _validate_transport_context(health_url, timeout_ms)
    return _transport_request("software_stop")


def _confirmed_action_request(
    health_url,
    operation,
    challenge,
    timeout_ms,
):
    _validate_transport_context(health_url, timeout_ms)
    supplied = "" if challenge is None else challenge
    if supplied and not _lower_hex_exact(supplied, 32):
        raise ValueError("local action challenge is invalid")
    return _transport_request(
        operation,
        {"challenge": supplied} if supplied else {},
    )


def request_motion_search(
    health_url,
    challenge=None,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    return _confirmed_action_request(
        health_url,
        "motion_search_arm",
        challenge,
        timeout_ms,
    )


def request_safety_configuration(
    health_url,
    challenge=None,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    return _confirmed_action_request(
        health_url,
        "safety_configure",
        challenge,
        timeout_ms,
    )


def request_petri_start(
    health_url,
    challenge=None,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    return _confirmed_action_request(
        health_url,
        "petri_start",
        challenge,
        timeout_ms,
    )


def request_reviewed_recovery(
    health_url,
    challenge=None,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    return _confirmed_action_request(
        health_url,
        "recovery_home",
        challenge,
        timeout_ms,
    )


def request_registration_verification(
    health_url,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    _validate_transport_context(health_url, timeout_ms)
    return _transport_request("registration_verify")


def request_manual_review(
    health_url,
    challenge=None,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    return _confirmed_action_request(
        health_url,
        "manual_review",
        challenge,
        timeout_ms,
    )


def request_workspace_teach_start(
    health_url,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    _validate_transport_context(health_url, timeout_ms)
    return _transport_request("workspace_teach_start")


def request_workspace_teach_capture(
    health_url,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    _validate_transport_context(health_url, timeout_ms)
    return _transport_request("workspace_teach_capture")


def request_workspace_teach_cancel(
    health_url,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    _validate_transport_context(health_url, timeout_ms)
    return _transport_request("workspace_teach_cancel")


def request_workspace_teach_finalize(
    health_url,
    challenge=None,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    return _confirmed_action_request(
        health_url,
        "workspace_teach_finalize",
        challenge,
        timeout_ms,
    )


def request_tenant_login(
    health_url,
    tenant_url,
    username,
    password,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    """Create one fixed local login request; no endpoint path is supplied."""

    _validate_transport_context(health_url, timeout_ms)
    return _transport_request(
        "tenant_login",
        {
            "tenant_url": tenant_url,
            "username": username,
            "password": password,
        },
    )


def request_tenant_logout(health_url, timeout_ms=DEFAULT_TIMEOUT_MS):
    _validate_transport_context(health_url, timeout_ms)
    return _transport_request("tenant_logout")


def request_hand_training_start(health_url, timeout_ms=DEFAULT_TIMEOUT_MS):
    _validate_transport_context(health_url, timeout_ms)
    return _transport_request("hand_training_start")


def request_hand_training_tool(
    health_url, active, timeout_ms=DEFAULT_TIMEOUT_MS
):
    _validate_transport_context(health_url, timeout_ms)
    if type(active) is not bool:
        raise ValueError("hand-training tool state is invalid")
    return _transport_request("hand_training_tool", {"active": active})


def request_hand_training_end(health_url, timeout_ms=DEFAULT_TIMEOUT_MS):
    _validate_transport_context(health_url, timeout_ms)
    return _transport_request("hand_training_end")


def _safe_registry_id(value):
    allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._-"
    return bool(
        isinstance(value, str)
        and 3 <= len(value) <= 64
        and value[0] in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        and all(character in allowed for character in value)
    )


def _valid_manual_review_candidate(candidate):
    if not isinstance(candidate, dict) or set(candidate) != {
        "observation_id",
        "plate_id",
        "cluster_id",
        "captured_at",
        "confidence",
        "area_px2",
    }:
        return False
    if not all(
        _safe_registry_id(candidate.get(name))
        for name in ("observation_id", "plate_id", "cluster_id")
    ):
        return False
    captured_at = candidate.get("captured_at")
    if (
        not isinstance(captured_at, str)
        or not 1 <= len(captured_at) <= 64
        or any(ord(character) < 32 for character in captured_at)
    ):
        return False
    confidence = candidate.get("confidence")
    area = candidate.get("area_px2")
    return bool(
        not isinstance(confidence, bool)
        and isinstance(confidence, (int, float))
        and 0 <= confidence <= 1
        and not isinstance(area, bool)
        and isinstance(area, (int, float))
        and 0 <= area <= 1000000000
    )


def _valid_confirmation_payload(payload, expires_max=5, extra_keys=()):
    expected = {"status", "challenge", "expires_in_seconds"} | set(extra_keys)
    expires = payload.get("expires_in_seconds")
    return bool(
        set(payload) == expected
        and payload.get("status") == "confirm"
        and _lower_hex_exact(payload.get("challenge"), 32)
        and isinstance(expires, int)
        and not isinstance(expires, bool)
        and 1 <= expires <= expires_max
    )


def _valid_completed_transport_payload(operation, status, payload):
    """Reject a broker result that could invent an accepted UI state."""

    if operation == "health":
        return isinstance(payload, dict)
    outcome = payload.get("status") if isinstance(payload, dict) else None
    if operation == "ota_check":
        return bool(
            set(payload) == {"status"}
            and outcome in ("accepted", "busy", "unavailable", "error")
        )
    if operation == "capture_start":
        if outcome == "confirm":
            return _valid_confirmation_payload(payload)
        return bool(
            set(payload) == {"status"}
            and outcome
            in (
                "accepted",
                "confirmation_required",
                "busy",
                "unsafe",
                "unavailable",
                "error",
            )
        )
    if operation == "capture_stop":
        return bool(
            set(payload) == {"status"}
            and outcome in ("accepted", "idle", "unavailable", "error")
        )
    if operation == "software_stop":
        return bool(
            set(payload) == {"status"}
            and outcome in ("accepted", "idle", "unavailable", "error")
        )
    if operation in ("motion_search_arm", "petri_start", "recovery_home"):
        if outcome == "confirm":
            return _valid_confirmation_payload(payload)
        return bool(
            set(payload) == {"status"}
            and outcome
            in (
                "accepted",
                "confirmation_required",
                "busy",
                "unsafe",
                "unavailable",
                "error",
            )
        )
    if operation == "safety_configure":
        if outcome == "confirm":
            return bool(
                _valid_confirmation_payload(payload, extra_keys=("profile_sha256",))
                and _lower_hex_exact(payload.get("profile_sha256"), 64)
            )
        if outcome == "configured":
            return bool(
                set(payload) == {"status", "profile_sha256"}
                and _lower_hex_exact(payload.get("profile_sha256"), 64)
            )
        return bool(
            set(payload) == {"status"}
            and outcome
            in (
                "confirmation_required",
                "aborted",
                "busy",
                "unsafe",
                "unavailable",
                "error",
            )
        )
    if operation == "registration_verify":
        return bool(
            set(payload) == {"status"}
            and outcome in ("verified", "incomplete", "busy", "unavailable", "error")
        )
    if operation == "manual_review":
        if outcome == "confirm":
            return bool(
                _valid_confirmation_payload(
                    payload,
                    expires_max=30,
                    extra_keys=("candidate",),
                )
                and _valid_manual_review_candidate(payload.get("candidate"))
            )
        if outcome == "accepted":
            return bool(
                set(payload) == {"status", "observation_id"}
                and _safe_registry_id(payload.get("observation_id"))
            )
        return bool(
            set(payload) == {"status"}
            and outcome
            in (
                "confirmation_required",
                "busy",
                "unavailable",
                "error",
            )
        )
    if operation in (
        "workspace_teach_start",
        "workspace_teach_capture",
        "workspace_teach_cancel",
        "workspace_teach_finalize",
    ):
        if not isinstance(payload, dict):
            return False
        outcome = payload.get("status")
        expected_errors = {
            "confirmation_required": 409,
            "busy": 409,
            "unsafe": 409,
            "unavailable": 503,
            "error": 500,
            "invalid_request": 400,
        }
        if outcome in expected_errors:
            return bool(
                set(payload) == {"status"} and status == expected_errors[outcome]
            )
        if operation in (
            "workspace_teach_start",
            "workspace_teach_capture",
        ):
            return bool(
                status == 202 and set(payload) == {"status"} and outcome == "accepted"
            )
        if operation == "workspace_teach_cancel":
            return bool(
                status == 200 and set(payload) == {"status"} and outcome == "cancelled"
            )
        if outcome == "confirm":
            return bool(
                status == 202
                and _valid_confirmation_payload(
                    payload,
                    expires_max=5,
                    extra_keys=("proposal_sha256",),
                )
                and payload.get("expires_in_seconds") == 5
                and _lower_hex_exact(payload.get("proposal_sha256"), 64)
            )
        return bool(
            status == 200
            and set(payload) == {"status", "proposal_sha256"}
            and outcome == "proposed"
            and _lower_hex_exact(payload.get("proposal_sha256"), 64)
        )
    if operation == "tenant_login":
        errors = {
            "invalid_tenant_url": 400,
            "insecure_tenant_url": 400,
            "missing_credentials": 400,
            "invalid_request": 400,
            "invalid_credentials": 401,
            "tenant_change_requires_logout": 409,
            "login_rejected": 403,
            "invalid_response": 503,
            "tenant_unavailable": 503,
            "unavailable": 503,
        }
        if outcome in errors:
            return bool(set(payload) == {"status"} and status == errors[outcome])
        expected = {
            "status",
            "tenant_url",
            "tenant",
            "username",
            "display_name",
            "access_expires_in",
            "session_persisted",
        }
        if "device_registration" in payload:
            expected.add("device_registration")
        if status != 200 or set(payload) != expected:
            return False
        registration = payload.get("device_registration")
        expires = payload.get("access_expires_in")
        return bool(
            outcome == "authenticated"
            and isinstance(payload.get("tenant_url"), str)
            and 1 <= len(payload["tenant_url"]) <= 512
            and isinstance(payload.get("tenant"), str)
            and 1 <= len(payload["tenant"]) <= 128
            and isinstance(payload.get("username"), str)
            and 1 <= len(payload["username"]) <= 254
            and isinstance(payload.get("display_name"), str)
            and len(payload["display_name"]) <= 254
            and isinstance(expires, int)
            and not isinstance(expires, bool)
            and 0 <= expires <= 31_536_000
            and isinstance(payload.get("session_persisted"), bool)
            and (
                registration is None
                or (
                    isinstance(registration, dict)
                    and set(registration)
                    == {
                        "uid_device",
                        "token",
                        "created",
                        "email_sent",
                        "email_recipient",
                    }
                    and isinstance(registration.get("uid_device"), str)
                    and 1 <= len(registration["uid_device"]) <= 100
                    and isinstance(registration.get("token"), str)
                    and 1 <= len(registration["token"]) <= 128
                    and type(registration.get("created")) is bool
                    and type(registration.get("email_sent")) is bool
                    and isinstance(registration.get("email_recipient"), str)
                )
            )
        )
    if operation == "tenant_logout":
        return bool(
            set(payload) == {"status"}
            and (
                (status == 200 and outcome == "logged_out")
                or (status == 503 and outcome in ("tenant_unavailable", "unavailable"))
            )
        )
    if operation in ("hand_training_start", "hand_training_end"):
        return bool(
            set(payload) == {"status"}
            and outcome
            in (
                "accepted",
                "idle",
                "busy",
                "unsafe",
                "login_required",
                "unavailable",
                "error",
            )
        )
    if operation == "hand_training_tool":
        if outcome == "accepted":
            return bool(
                set(payload) == {"status", "tool_on"}
                and isinstance(payload.get("tool_on"), bool)
            )
        return bool(
            set(payload) == {"status"}
            and outcome
            in ("unsafe", "unavailable", "invalid_request", "error")
        )
    return (
        operation
        in (
            "snapshot_tool",
            "snapshot_workspace",
            "manual_review_preview",
        )
        and status != 200
    )


def fetch_camera_snapshot(
    health_url,
    role,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    _validate_transport_context(health_url, timeout_ms)
    if role not in ("tool", "workspace"):
        raise ValueError("camera role is not allowlisted")
    return _transport_request("snapshot_" + role)


def fetch_manual_review_preview(
    health_url,
    timeout_ms=DEFAULT_TIMEOUT_MS,
):
    _validate_transport_context(health_url, timeout_ms)
    return _transport_request("manual_review_preview")


def _mapping(value):
    return value if isinstance(value, dict) else {}


def _lower_hex(value, length):
    return bool(
        isinstance(value, str)
        and len(value) == length
        and all(character in "0123456789abcdef" for character in value)
    )


def _runtime_role_view(source):
    """Return bounded branding derived only from a known deployment mode."""

    raw = (
        _mapping(source).get("deployment_mode") if isinstance(source, dict) else source
    )
    mode = raw if isinstance(raw, str) else ""
    roles = {
        "gateway": {
            "mode": "gateway",
            "role": "GATEWAY READ-ONLY",
            "subtitle": "DUAL VISION GATEWAY / READ-ONLY STATUS",
            "online": "GATEWAY ONLINE",
            "check": "CHECK GATEWAY",
        },
        "operator": {
            "mode": "operator",
            "role": "OPERATOR CONTROL",
            "subtitle": "DUAL VISION OPERATOR / BOUNDED CONTROL",
            "online": "OPERATOR ONLINE",
            "check": "CHECK OPERATOR",
        },
        "production": {
            "mode": "production",
            "role": "PRODUCTION CONTROL",
            "subtitle": "DUAL VISION PRODUCTION / BOUNDED CONTROL",
            "online": "PRODUCTION ONLINE",
            "check": "CHECK PRODUCTION",
        },
        "workcell": {
            "mode": "workcell",
            "role": "WORKCELL CAPTURE",
            "subtitle": "DUAL VISION WORKCELL / CAPTURE STATUS",
            "online": "WORKCELL ONLINE",
            "check": "CHECK WORKCELL",
        },
        "development": {
            "mode": "development",
            "role": "DEVELOPMENT",
            "subtitle": "DUAL VISION DEVELOPMENT / LOCAL STATUS",
            "online": "DEVELOPMENT",
            "check": "CHECK DEVELOPMENT",
        },
    }
    return roles.get(
        mode,
        {
            "mode": "unknown",
            "role": "RUNTIME ROLE UNKNOWN",
            "subtitle": "DUAL VISION RUNTIME / ROLE NOT VERIFIED",
            "online": "RUNTIME ONLINE",
            "check": "CHECK RUNTIME",
        },
    )


def _counter_text(value):
    # The pinned LVGL MicroPython Unix runtime has a native ``int(None)``
    # crash instead of raising TypeError.  Counter fields are untrusted health
    # data, so validate their shape and parse decimal strings without ever
    # passing an arbitrary object to ``int``.
    if isinstance(value, bool) or value is None:
        return "--"
    if isinstance(value, int):
        parsed = value
    elif isinstance(value, str):
        text = value.strip()
        if not text or len(text) > 16:
            return "--"
        parsed = 0
        for character in text:
            if character < "0" or character > "9":
                return "--"
            parsed = parsed * 10 + (ord(character) - ord("0"))
            if parsed > 999999999:
                return "999M+"
    else:
        return "--"
    if parsed < 0:
        return "--"
    if parsed > 999999999:
        return "999M+"
    return str(parsed)


def _camera_age_text(camera, now_seconds=None):
    """Return one bounded freshness age without trusting wall-clock shape."""

    age = camera.get("sample_age_seconds")
    if isinstance(age, bool) or not isinstance(age, (int, float)):
        captured_at = camera.get("last_frame_at_s")
        if isinstance(captured_at, bool) or not isinstance(captured_at, (int, float)):
            return "--"
        if now_seconds is None:
            try:
                now_seconds = time.time()
            except Exception:
                return "--"
        if isinstance(now_seconds, bool) or not isinstance(now_seconds, (int, float)):
            return "--"
        age = now_seconds - captured_at
    if age != age or age < 0 or age > 86400:
        return "--"
    if age < 10:
        return "%.1f S" % age
    if age <= 999:
        return "%d S" % int(age)
    return "999+ S"


def _camera_identity_text(value):
    value = _safe_text(value, 80)
    if not value:
        return "--"
    if len(value) <= 36:
        return value
    return "%s...%s" % (value[:16], value[-16:])


def _camera_view(cameras, role, identity=None, now_seconds=None):
    # ``str.capitalize`` crashes in the target-proven MicroPython Unix build.
    # Camera roles are a closed set, so render their labels without it.
    role_label = "Tool" if role == "tool" else "Workspace"
    eyebrow = "TOOL CAMERA" if role == "tool" else "WORKSPACE CAMERA"
    camera = dict(_mapping(_mapping(cameras).get(role)))
    has_camera_status = bool(camera)
    identity = _mapping(identity)
    for key in ("backend", "source_id", "mxid"):
        if not camera.get(key) and identity.get(key):
            camera[key] = identity.get(key)
    backend = _safe_text(camera.get("backend") or "unknown", 16).lower()
    if backend not in ("depthai", "opencv", "unknown"):
        backend = "unknown"
    mxid = _camera_identity_text(camera.get("mxid"))
    source_id = _camera_identity_text(camera.get("source_id"))
    identity_kind = "MXID" if mxid != "--" else "SOURCE"
    identity_value = mxid if mxid != "--" else source_id
    age = _camera_age_text(camera, now_seconds)
    sequence = _counter_text(
        camera.get("sequence")
        if camera.get("sequence") is not None
        else camera.get("frames_captured")
    )
    if not has_camera_status:
        return {
            "role": role_label,
            "eyebrow": eyebrow,
            "healthy": False,
            "tone": "muted",
            "headline": "UNAVAILABLE",
            "detail": "No camera status received",
            "frames": "--",
            "reconnects": "--",
            "errors": "--",
            "backend": backend.upper(),
            "identity_kind": identity_kind,
            "identity": identity_value,
            "age": age,
            "sequence": sequence,
            "legacy": "%s: unavailable" % role_label,
        }

    state = _safe_text(camera.get("state") or "unknown", 24)
    fresh = camera.get("fresh") is True
    healthy = state == "running" and fresh
    if healthy:
        headline = "STREAMING"
        detail = "Fresh OAK-D Lite frames"
        tone = "ok"
    elif state == "reconnecting":
        headline = "RECONNECTING"
        detail = "Waiting for fresh frames"
        tone = "warn"
    elif state == "running":
        headline = "STALE FRAMES"
        detail = "Pipeline is running, image is stale"
        tone = "warn"
    elif state == "degraded":
        headline = "CAMERA FAULT"
        detail = "Camera pipeline needs attention"
        tone = "danger"
    else:
        headline = "CHECK CAMERA"
        detail = "State: %s" % state
        tone = "warn"
    freshness = "fresh" if fresh else "stale"
    return {
        "role": role_label,
        "eyebrow": eyebrow,
        "healthy": healthy,
        "tone": tone,
        "headline": headline,
        "detail": detail,
        "frames": _counter_text(camera.get("frames_captured")),
        "reconnects": _counter_text(camera.get("reconnects")),
        "errors": _counter_text(camera.get("consecutive_errors")),
        "backend": backend.upper(),
        "identity_kind": identity_kind,
        "identity": identity_value,
        "age": age,
        "sequence": sequence,
        "legacy": "%s: %s / %s" % (role_label, state, freshness),
    }


def _camera_text(cameras, role):
    return _camera_view(cameras, role)["legacy"]


def _motion_view(runtime):
    runtime = _mapping(runtime)
    capture = _mapping(runtime.get("capture_run"))
    capture_state = _safe_text(capture.get("state") or "", 24)
    if (
        capture.get("schema_version") == 1
        and capture.get("configured") is True
        and capture_state == "fault_locked"
    ):
        return {
            "tone": "danger",
            "headline": "CAPTURE MOTION FAULT",
            "detail": "NOT-AUS betaetigen und Anlage pruefen",
            "policy": "Keinen neuen Lauf starten",
            "badge": "FAULT LOCKED",
            "verified_locked": False,
        }
    if (
        capture.get("schema_version") == 1
        and capture.get("configured") is True
        and capture.get("active") is True
        and capture.get("motion_started") is True
        and capture_state in ("starting", "running", "stopping")
    ):
        return {
            "tone": "danger",
            "headline": "CAPTURE MOTION ACTIVE",
            "detail": "15-Sekunden-Bewegung wird ausgefuehrt",
            "policy": "Arbeitsraum frei halten; STOP ist verfuegbar",
            "badge": "LIVE MOTION",
            "verified_locked": False,
        }

    motion = _mapping(runtime.get("motion"))
    if not motion:
        return {
            "tone": "muted",
            "headline": "STATUS UNKNOWN",
            "detail": "No motion safety status received",
            "policy": "Verify the local runtime",
            "badge": "NOT VERIFIED",
            "verified_locked": False,
        }

    state = _safe_text(motion.get("state") or "UNKNOWN", 24)
    fault = _safe_text(motion.get("fault") or "", 40)
    # A commissioned robot-control owner can be capable while its authorization
    # gate is safely closed.  Capability is not motion: LOCKED + unarmed +
    # non-live + no fault is the authoritative safe condition in every mode.
    locked = (
        state == "LOCKED"
        and isinstance(motion.get("capable"), bool)
        and motion.get("armed") is False
        and motion.get("live") is False
        and not fault
    )
    if locked:
        xarm = _xarm_view(runtime)
        if xarm.get("motion_ready") is not True:
            error_two = xarm.get("error_code") == 2
            system_check_ok = xarm.get("system_check_ok") is True
            return {
                "tone": (
                    "danger" if error_two or xarm.get("tone") == "danger" else "warn"
                ),
                "headline": (
                    "EMERGENCY-IO OPEN"
                    if error_two
                    else (
                        "ROBOT CONTROL SETUP REQUIRED"
                        if system_check_ok
                        else "xARM CHECK REQUIRED"
                    )
                ),
                "detail": (
                    "Controller system check OK; motion safeguards need setup"
                    if system_check_ok
                    else (xarm.get("guidance") or "xArm health is not verified")
                ),
                "policy": "No motion until every xArm and workcell gate passes",
                "badge": (
                    "MOTION SETUP REQUIRED" if system_check_ok else "MOTION BLOCKED"
                ),
                "verified_locked": False,
            }
        commissioned = motion.get("capable") is True
        return {
            "tone": "ok",
            "headline": "MOTION LOCKED",
            "detail": "Commands remain disabled",
            "policy": (
                "Commissioned owner locked; two-step action required"
                if commissioned
                else "Read-only gateway policy"
            ),
            "badge": "SAFE STATE VERIFIED",
            "verified_locked": True,
        }
    if state == "FAULT_LOCKED" or fault:
        return {
            "tone": "danger",
            "headline": "SAFETY FAULT",
            "detail": fault or "Motion controller is fault locked",
            "policy": "Operator review required",
            "badge": "FAULT LOCKED",
            "verified_locked": False,
        }
    if state == "ARMED_LIVE" or motion.get("armed") is True:
        return {
            "tone": "danger",
            "headline": "MOTION ENABLED",
            "detail": "Live authorization is active",
            "policy": "Keep clear of the robot",
            "badge": "LIVE MOTION",
            "verified_locked": False,
        }
    return {
        "tone": "warn",
        "headline": "VERIFY SAFETY",
        "detail": "Motion state: %s" % state,
        "policy": "Runtime state is inconsistent",
        "badge": "REVIEW REQUIRED",
        "verified_locked": False,
    }


def _ota_view(runtime):
    ota = _mapping(_mapping(runtime).get("ota"))
    unavailable = {
        "configured": False,
        "action_allowed": False,
        "status": "unavailable",
        "tone": "muted",
        "headline": "UPDATE NICHT VERFUEGBAR",
        "detail": "Signed OTA is not configured",
        "current_version": "--",
        "available_version": "--",
        "button": "NICHT VERFUEGBAR",
        "verification_badge": "NOT CONFIGURED",
        "verification_tone": "muted",
        "manifest_verification": "not_available",
        "archive_digest_verification": "not_required",
        "auto_apply_requested": False,
        "auto_apply_permitted": False,
        "commissioning_blocker": "",
    }
    schema_version = ota.get("schema_version")
    if schema_version not in (1, 2) or ota.get("configured") is not True:
        return unavailable
    auto_apply_requested = False
    auto_apply_permitted = False
    commissioning_blocker = ""
    if schema_version == 2:
        commissioning = _mapping(ota.get("commissioning"))
        blockers = commissioning.get("blockers")
        allowed_blockers = {
            "rollback_switch_active",
            "commissioning_path_missing",
            "commissioning_path_unsafe",
            "commissioning_digest_missing",
            "commissioning_digest_mismatch",
            "commissioning_artifact_invalid",
            "commissioning_expired",
            "commissioning_device_mismatch",
            "commissioning_release_mismatch",
            "commissioning_camera_mismatch",
            "commissioning_controller_mismatch",
            "commissioning_boot_supervisor_mismatch",
            "commissioning_filesystem_mismatch",
            "commissioning_lvgl_mismatch",
            "commissioning_evidence_incomplete",
        }
        if (
            not isinstance(ota.get("auto_apply_requested"), bool)
            or not isinstance(ota.get("auto_apply_permitted"), bool)
            or set(commissioning) != {"blockers", "required", "valid"}
            or not isinstance(commissioning.get("required"), bool)
            or not isinstance(commissioning.get("valid"), bool)
            or not isinstance(blockers, list)
            or len(blockers) > len(allowed_blockers)
            or len(set(blockers)) != len(blockers)
            or any(value not in allowed_blockers for value in blockers)
            or commissioning["required"] is not ota["auto_apply_requested"]
            or commissioning["valid"] is not ota["auto_apply_permitted"]
            or (commissioning["valid"] and blockers)
            or (ota["auto_apply_permitted"] and not ota["auto_apply_requested"])
        ):
            invalid = dict(unavailable)
            invalid.update(
                {
                    "configured": True,
                    "tone": "danger",
                    "headline": "COMMISSIONING-NACHWEIS UNGUELTIG",
                    "detail": "Auto-Update bleibt gesperrt",
                    "verification_badge": "COMMISSIONING INVALID",
                    "verification_tone": "danger",
                }
            )
            return invalid
        auto_apply_requested = ota["auto_apply_requested"]
        auto_apply_permitted = ota["auto_apply_permitted"]
        commissioning_blocker = blockers[0] if blockers else ""
    status = _safe_text(ota.get("status") or "unknown", 32)
    known = (
        "idle",
        "checking",
        "up_to_date",
        "update_available",
        "busy",
        "pending_restart",
        "error",
        "unavailable",
    )
    if status not in known:
        return unavailable
    current_version = _safe_text(ota.get("current_version") or "--", 32)
    available_version = _safe_text(
        ota.get("available_version") or "--",
        32,
    )
    manifest_verification = ota.get("manifest_verification")
    archive_verification = ota.get("archive_digest_verification")
    manifest_states = (
        "not_checked",
        "not_available",
        "checking",
        "verified",
        "failed",
    )
    archive_states = (
        "not_checked",
        "not_required",
        "checking",
        "verified",
        "failed",
    )
    if (
        manifest_verification not in manifest_states
        or archive_verification not in archive_states
    ):
        return {
            "configured": True,
            "action_allowed": False,
            "status": status,
            "tone": "danger",
            "headline": "UPDATE-NACHWEIS UNGUELTIG",
            "detail": "Signatur- oder Archivdigeststatus fehlt oder ist ungueltig",
            "current_version": current_version,
            "available_version": available_version,
            "button": "NACHWEIS PRUEFEN",
            "verification_badge": "SIG INVALID / SHA INVALID",
            "verification_tone": "danger",
            "manifest_verification": "invalid",
            "archive_digest_verification": "invalid",
            "auto_apply_requested": auto_apply_requested,
            "auto_apply_permitted": False,
            "commissioning_blocker": commissioning_blocker,
        }
    manifest_labels = {
        "not_checked": "SIG --",
        "not_available": "SIG N/A",
        "checking": "SIG CHECK",
        "verified": "SIG VERIFIED",
        "failed": "SIG FAILED",
    }
    archive_labels = {
        "not_checked": "SHA --",
        "not_required": "SHA N/A",
        "checking": "SHA CHECK",
        "verified": "SHA VERIFIED",
        "failed": "SHA FAILED",
    }
    verification_badge = "%s / %s" % (
        manifest_labels[manifest_verification],
        archive_labels[archive_verification],
    )
    action_allowed = ota.get("action_allowed") is True and status in (
        "idle",
        "up_to_date",
        "error",
    )
    if status == "idle":
        if commissioning_blocker == "rollback_switch_active":
            headline = "AUTO-UPDATE ROLLBACK AKTIV"
            detail = "Geplante Installation ist lokal deaktiviert"
        else:
            headline = (
                "UPDATE-CHECK BEREIT" if action_allowed else "UPDATE-CHECK GESPERRT"
            )
            detail = (
                "Backend prueft Manifest und Signatur erst nach Tastendruck"
                if action_allowed
                else "Backend-Aktion ist derzeit nicht freigegeben"
            )
        tone = "warn"
        verification_tone = "warn"
    elif status == "up_to_date":
        if (
            manifest_verification == "verified"
            and archive_verification == "not_required"
        ):
            headline = "SYSTEM IST AKTUELL"
            detail = "Signiertes Manifest bestaetigt: keine neuere Version"
            tone = "ok"
            verification_tone = "ok"
        else:
            headline = "UPDATE-NACHWEIS UNVOLLSTAENDIG"
            detail = "Up-to-date darf nur mit verifizierter Signatur erscheinen"
            tone = "danger"
            verification_tone = "danger"
            action_allowed = False
    elif status == "update_available":
        if (
            manifest_verification == "verified"
            and archive_verification == "not_required"
        ):
            headline = "SIGNIERTES UPDATE VERFUEGBAR"
            detail = "Installation bleibt bis zum sicheren Backend-Gate gesperrt"
            tone = "warn"
            verification_tone = "ok"
        else:
            headline = "UPDATE-NACHWEIS UNVOLLSTAENDIG"
            detail = "Verfuegbares Update erfordert eine verifizierte Signatur"
            tone = "danger"
            verification_tone = "danger"
            action_allowed = False
    elif status in ("checking", "busy"):
        headline = "UPDATE WIRD GEPRUEFT"
        detail = "Manifest und Signatur werden validiert"
        tone = "warn"
        if "failed" in (manifest_verification, archive_verification):
            headline = "UPDATE-PRUEFUNG FEHLGESCHLAGEN"
            detail = "Signatur- oder Archivdigestpruefung ist fehlgeschlagen"
            tone = "danger"
            verification_tone = "danger"
        else:
            verification_tone = "warn"
    elif status == "pending_restart":
        if manifest_verification == "verified" and archive_verification == "verified":
            headline = "NEUSTART WIRD VORBEREITET"
            detail = "Signatur und Archivdigest verifiziert; Neustart steht aus"
            tone = "warn"
            verification_tone = "ok"
        else:
            headline = "UPDATE-NACHWEIS UNVOLLSTAENDIG"
            detail = "Pending restart erfordert Signatur- und Digestnachweis"
            tone = "danger"
            verification_tone = "danger"
            action_allowed = False
    elif status == "error":
        headline = "UPDATE FEHLGESCHLAGEN"
        detail = "Update-Dienst und erforderliche Server-Migration pruefen"
        tone = "danger"
        verification_tone = "danger"
    else:
        headline = "AUTO-UPDATE COMMISSIONING GESPERRT"
        detail = (
            commissioning_blocker.replace("_", " ").upper()
            if commissioning_blocker
            else "Update-Dienst ist derzeit nicht verfuegbar"
        )
        tone = "warn" if commissioning_blocker else "muted"
        verification_tone = tone
        action_allowed = False
    return {
        "configured": True,
        "action_allowed": action_allowed,
        "status": status,
        "tone": tone,
        "headline": headline,
        "detail": detail,
        "current_version": current_version,
        "available_version": available_version,
        "button": "JETZT UPDATEN" if action_allowed else "BITTE WARTEN",
        "verification_badge": verification_badge,
        "verification_tone": verification_tone,
        "manifest_verification": manifest_verification,
        "archive_digest_verification": archive_verification,
        "auto_apply_requested": auto_apply_requested,
        "auto_apply_permitted": auto_apply_permitted,
        "commissioning_blocker": commissioning_blocker,
    }


def _capture_view(runtime):
    capture = _mapping(_mapping(runtime).get("capture_run"))
    unavailable = {
        "configured": False,
        "active": False,
        "action_allowed": False,
        "stop_allowed": False,
        "state": "unavailable",
        "tone": "muted",
        "headline": "LAUF NICHT FREIGEGEBEN",
        "detail": "Gepruefter 15-Sekunden-Bewegungspfad fehlt",
        "button": "NICHT FREIGEGEBEN",
        "run_id": "--",
        "completed_timepoints": 0,
        "planned_timepoints": 15,
        "tool_saved": 0,
        "workspace_saved": 0,
        "saved_images": 0,
        "progress": 0,
        "motion_started": False,
        "dataset_state": "unavailable",
        "dataset_tone": "warn",
        "dataset_text": "DATASET: SENDUNG NICHT BESTAETIGT",
        "dataset_acknowledged": 0,
        "dataset_pending": 0,
        "dataset_dead_lettered": 0,
        "error_code": "--",
        "manifest_state": "unavailable",
        "manifest_complete": False,
        "evidence_text": "LOCAL MANIFEST UNAVAILABLE | ERR --",
        "evidence_tone": "muted",
        "blocker": "Capture backend is not commissioned",
    }
    schema_version = capture.get("schema_version")
    if isinstance(schema_version, bool) or schema_version != 1:
        return unavailable
    if capture.get("configured") is not True:
        return unavailable
    active = capture.get("active")
    if not isinstance(active, bool):
        return unavailable
    duration = capture.get("duration_seconds")
    interval = capture.get("interval_seconds")
    counters = (
        capture.get("planned_timepoints"),
        capture.get("completed_timepoints"),
        capture.get("tool_saved"),
        capture.get("workspace_saved"),
        capture.get("saved_images"),
    )
    if (
        isinstance(duration, bool)
        or not isinstance(duration, (int, float))
        or isinstance(interval, bool)
        or not isinstance(interval, (int, float))
        or any(
            isinstance(value, bool) or not isinstance(value, int) for value in counters
        )
    ):
        return unavailable
    planned, completed, tool_saved, workspace_saved, saved_images = counters
    if (
        duration != 15.0
        or interval != 1.0
        or planned != 15
        or not 0 <= completed <= planned
        or not 0 <= tool_saved <= planned
        or not 0 <= workspace_saved <= planned
        or not 0 <= saved_images <= planned * 2
        or tool_saved != completed
        or workspace_saved != completed
        or saved_images != completed * 2
    ):
        return unavailable
    state = _safe_text(capture.get("state") or "unknown", 24)
    known = (
        "idle",
        "confirming",
        "starting",
        "running",
        "stopping",
        "completed",
        "cancelled",
        "failed",
        "interrupted",
        "fault_locked",
    )
    if state not in known:
        return unavailable
    raw_error_code = capture.get("error_code")
    if (
        not isinstance(raw_error_code, str)
        or len(raw_error_code) > 48
        or any(
            character not in "abcdefghijklmnopqrstuvwxyz0123456789_"
            for character in raw_error_code
        )
    ):
        return unavailable
    manifest_state = capture.get("local_manifest_state")
    manifest_complete = capture.get("local_manifest_complete")
    manifest_states = (
        "none",
        "starting",
        "running",
        "stopping",
        "completed",
        "cancelled",
        "failed",
        "interrupted",
        "fault_locked",
        "invalid",
    )
    if (
        manifest_state not in manifest_states
        or not isinstance(manifest_complete, bool)
        or (state == "completed" and completed != planned)
        or (
            state == "completed"
            and not (manifest_state == "completed" and manifest_complete is True)
        )
        or (manifest_complete is True and state != "completed")
    ):
        return unavailable
    export = _capture_export_view(runtime, capture.get("run_id"), state)
    error_code = raw_error_code or "--"
    backend_message = _operation_message(capture.get("message"), 72)
    action_allowed = (
        capture.get("action_allowed") is True
        and export["new_run_allowed"] is True
        and state
        in (
            "idle",
            "confirming",
            "completed",
            "cancelled",
            "failed",
            "interrupted",
        )
    )
    stop_allowed = capture.get("stop_allowed") is True and state in (
        "starting",
        "running",
        "stopping",
    )
    blocker = ""
    if capture.get("action_allowed") is not True:
        blocker = backend_message or "Backend hat den Lauf nicht freigegeben"
    elif export["new_run_allowed"] is not True:
        blocker = "Vorherigen Dataset-Export zuerst abschliessen"
    if state == "idle" and action_allowed:
        headline = "BEREIT FUER 15 S LAUF"
        detail = "15 Bildpaare - einmal pro Sekunde"
        tone = "ok"
    elif state == "idle":
        headline = "LAUF GESPERRT"
        detail = blocker or "Backend-Freigabe fehlt"
        tone = "danger" if error_code != "--" else "warn"
    elif state == "confirming":
        headline = "START ERNEUT BESTAETIGEN"
        detail = "Arbeitsraum frei und Not-Aus erreichbar?"
        tone = "warn"
    elif state == "starting":
        headline = "LAUF STARTET"
        detail = "Motion-Watchdog und Dataset werden vorbereitet"
        tone = "warn"
    elif state == "running":
        headline = "AUFNAHME LAEUFT"
        detail = "Beide OAK-D Lite werden synchron gespeichert"
        tone = "warn"
    elif state == "stopping":
        headline = "STOPP WIRD AUSGEFUEHRT"
        detail = "Bewegung wird verriegelt und Dataset abgeschlossen"
        tone = "warn"
    elif state == "completed":
        if export["state"] == "synced":
            headline = "DATASET GESPEICHERT + GESENDET"
            detail = "30 Bilder lokal und im Ziel-Dataset bestaetigt"
            tone = "ok"
        elif export["state"] == "failed":
            headline = "30 BILDER LOKAL GESPEICHERT"
            detail = "Dataset-Sendung fehlgeschlagen - lokale Daten bleiben erhalten"
            tone = "danger"
        else:
            headline = "30 BILDER LOKAL GESPEICHERT"
            detail = "Dataset-Sendung laeuft oder wartet auf Quittung"
            tone = "warn"
    elif state == "cancelled":
        headline = "LAUF ABGEBROCHEN"
        detail = "Teil-Dataset bleibt fuer die Pruefung erhalten"
        tone = "warn"
    elif state == "interrupted":
        headline = "LAUF UNTERBROCHEN"
        detail = "Unvollstaendiges Dataset wurde sicher markiert"
        tone = "danger"
    elif state == "fault_locked":
        headline = "SICHERHEITSFEHLER - BEWEGUNG GESPERRT"
        detail = "ANLAGE PRUEFEN; NOT-AUS WENN BEWEGUNG FORTBESTEHT"
        tone = "danger"
    else:
        headline = "LAUF FEHLGESCHLAGEN"
        detail = _safe_text(capture.get("message") or "Pruefung erforderlich", 64)
        tone = "danger"
    if state == "fault_locked":
        button = "NOT-AUS BETAETIGEN"
    elif stop_allowed:
        button = "SOFORT STOPPEN"
    elif action_allowed and state == "confirming":
        button = "NOCHMAL BESTAETIGEN"
    elif action_allowed:
        button = "15 S LAUF STARTEN"
    else:
        button = "BITTE WARTEN"
    if manifest_complete:
        evidence_tone = "ok"
        manifest_text = "COMPLETE"
    elif manifest_state == "invalid" or error_code != "--":
        evidence_tone = "danger"
        manifest_text = manifest_state.upper()
    elif manifest_state == "none":
        evidence_tone = "muted"
        manifest_text = "NONE"
    else:
        evidence_tone = "warn"
        manifest_text = manifest_state.upper()
    evidence_text = "LOCAL MANIFEST %s | ERR %s" % (manifest_text, error_code)
    return {
        "configured": True,
        "active": active,
        "action_allowed": action_allowed,
        "stop_allowed": stop_allowed,
        "state": state,
        "tone": tone,
        "headline": headline,
        "detail": detail,
        "button": button,
        "run_id": _safe_text(capture.get("run_id") or "--", 48),
        "completed_timepoints": completed,
        "planned_timepoints": planned,
        "tool_saved": tool_saved,
        "workspace_saved": workspace_saved,
        "saved_images": saved_images,
        "progress": int(100 * completed / planned),
        "motion_started": capture.get("motion_started") is True,
        "dataset_state": export["state"],
        "dataset_tone": export["tone"],
        "dataset_text": export["text"],
        "dataset_acknowledged": export["acknowledged_frames"],
        "dataset_pending": export["pending_frames"],
        "dataset_dead_lettered": export["dead_lettered_frames"],
        "error_code": error_code,
        "manifest_state": manifest_state,
        "manifest_complete": manifest_complete,
        "evidence_text": _safe_text(evidence_text, 96),
        "evidence_tone": evidence_tone,
        "blocker": blocker,
    }


def _capture_export_view(runtime, capture_run_id, capture_state):
    unavailable = {
        "valid": False,
        "state": "unavailable",
        "tone": "warn",
        "new_run_allowed": False,
        "acknowledged_frames": 0,
        "pending_frames": 0,
        "dead_lettered_frames": 0,
        "text": "DATASET: SENDUNG NICHT BESTAETIGT",
    }
    export = _mapping(_mapping(runtime).get("capture_export"))
    if export.get("schema_version") != 1 or export.get("configured") is not True:
        return unavailable
    state = _safe_text(export.get("state") or "", 24)
    if state not in (
        "scanning",
        "idle",
        "awaiting_export",
        "queueing",
        "sending",
        "synced",
        "failed",
    ):
        return unavailable
    fields = (
        export.get("total_frames"),
        export.get("known_frames"),
        export.get("unqueued_frames"),
        export.get("pending_frames"),
        export.get("acknowledged_frames"),
        export.get("dead_lettered_frames"),
    )
    if any(isinstance(value, bool) or not isinstance(value, int) for value in fields):
        return unavailable
    total, known, unqueued, pending, acknowledged, dead = fields
    if (
        total != 30
        or not 0 <= known <= total
        or not 0 <= unqueued <= total
        or not 0 <= pending <= total
        or not 0 <= acknowledged <= total
        or not 0 <= dead <= total
        or known + unqueued != total
        or pending + acknowledged + dead != known
        or not isinstance(export.get("new_run_allowed"), bool)
        or not isinstance(export.get("dataset_binding_verified"), bool)
    ):
        return unavailable
    raw_capture_id = capture_run_id if isinstance(capture_run_id, str) else ""
    export_run_id = export.get("run_id")
    if not isinstance(export_run_id, str):
        return unavailable
    if capture_state == "completed" and (
        not raw_capture_id or export_run_id != raw_capture_id
    ):
        return unavailable
    if state == "synced" and not (
        capture_state == "completed"
        and acknowledged == total
        and pending == 0
        and dead == 0
        and export.get("dataset_binding_verified") is True
    ):
        return unavailable

    if state == "synced":
        tone = "ok"
        text = "DATASET: 30 / 30 SERVER-BESTAETIGT"
    elif state == "failed" or dead:
        tone = "danger"
        text = "DATASET: SENDUNG FEHLER / PRUEFUNG NOETIG"
    elif state in ("sending", "queueing", "awaiting_export"):
        tone = "warn"
        text = "DATASET: %d / 30 GESENDET, %d WARTEND" % (
            acknowledged,
            pending + unqueued,
        )
    elif state == "scanning":
        tone = "warn"
        text = "DATASET: LIEFERQUITTUNGEN WERDEN GEPRUEFT"
    else:
        tone = "muted"
        text = "DATASET: BEREIT FUER 30 BILDER"
    return {
        "valid": True,
        "state": state,
        "tone": tone,
        "new_run_allowed": export.get("new_run_allowed") is True,
        "acknowledged_frames": acknowledged,
        "pending_frames": pending,
        "dead_lettered_frames": dead,
        "text": text,
    }


def _motion_search_view(view):
    """Reduce the single commissioned camera-guided motion action."""

    view = _mapping(view)
    raw = _mapping(view.get("motion_search"))
    unavailable = {
        "configured": False,
        "action_allowed": False,
        # Requesting the fixed local two-step endpoint is always safe: the
        # backend remains authoritative and can return an exact gate result.
        # This is not permission to move and must never be folded into
        # `action_allowed`.
        "request_allowed": True,
        "request_result": "",
        "state": "unavailable",
        "tone": "muted",
        "headline": "WERKZEUGSUCHE NICHT KONFIGURIERT",
        "detail": "Der gepruefte lokale Suchpfad ist noch nicht konfiguriert",
        "button": "SEARCH PATH START",
        "review": "Noch kein geprueftes Ziel ausgefuehrt",
        "workflow_progress": 0,
        "workflow_stage": "0 / 4  NICHT KONFIGURIERT",
        "stop_allowed": False,
    }
    if raw.get("schema_version") != 1:
        return unavailable
    deployment_mode = _safe_text(raw.get("deployment_mode") or "", 16)
    configured = raw.get("configured") is True
    state = _safe_text(raw.get("state") or "unavailable", 24)
    if state not in (
        "unavailable",
        "locked",
        "ready",
        "armed_live",
        "fault_locked",
        "busy",
    ):
        return unavailable
    two_step = raw.get("requires_two_step_confirmation") is True
    action_allowed = bool(
        deployment_mode in ("production", "operator")
        and configured
        and two_step
        and state == "ready"
        and raw.get("action_allowed") is True
    )
    review = _mapping(raw.get("last_target_review"))
    review_status = _safe_text(review.get("status") or "none", 28)
    confidence = review.get("confidence")
    if (
        isinstance(confidence, bool)
        or not isinstance(confidence, (int, float))
        or not 0.0 <= confidence <= 1.0
    ):
        confidence_text = "--"
    else:
        confidence_text = "%d%%" % int(confidence * 100)
    review_text = "LETZTES ZIEL: %s / CONF %s" % (
        review_status.upper(),
        confidence_text,
    )
    joint_waypoints = review.get("joint_waypoints")
    if (
        isinstance(joint_waypoints, int)
        and not isinstance(joint_waypoints, bool)
        and 0 <= joint_waypoints <= 1000
    ):
        review_text += " / PLAN %d" % joint_waypoints
    if state == "ready" and action_allowed:
        headline = "KAMERA-GEFUEHRTE WERKZEUGSUCHE BEREIT"
        detail = "Zweimal bestaetigen; danach genau ein validierter Suchlauf"
        tone = "ok"
        button = "SEARCH PATH START"
        workflow_progress = 25
        workflow_stage = "1 / 4  SAFETY-GATES BEREIT"
    elif state == "armed_live":
        headline = "WERKZEUGSUCHE AKTIV"
        detail = "Gepruefter Suchlauf aktiv; SOFTWARE STOP bleibt sichtbar"
        tone = "danger"
        button = "SOFTWARE STOP"
        workflow_progress = 75
        workflow_stage = "3 / 4  ROBOTER-SUCHLAUF AKTIV"
    elif state == "fault_locked":
        headline = "BEWEGUNG FEHLER-VERRIEGELT"
        detail = "Anlage pruefen; keine neue Suche freigeben"
        tone = "danger"
        button = "SOFTWARE STOP"
        workflow_progress = 100
        workflow_stage = "4 / 4  FEHLER-VERRIEGELT"
    elif state == "busy":
        headline = "PHYSISCHE OPERATION LAEUFT"
        detail = "Warten oder den sichtbaren SOFTWARE STOP benutzen"
        tone = "warn"
        button = "BITTE WARTEN"
        workflow_progress = 75
        workflow_stage = "3 / 4  PHYSISCHE OPERATION LAEUFT"
    elif deployment_mode not in ("production", "operator"):
        headline = "ROBOT CONTROL MODE NICHT AKTIV"
        detail = "Lokale Robotersteuerung ist noch nicht eingerichtet"
        tone = "warn"
        button = "SEARCH PATH START"
        state = "locked" if configured else "unavailable"
        workflow_progress = 0
        workflow_stage = "0 / 4  CONTROL SETUP"
    elif configured:
        headline = "WERKZEUGSUCHE GESPERRT"
        detail = "xArm, Kalibrierung, Kameras und Safety-Gates zuerst pruefen"
        tone = "warn"
        button = "SEARCH PATH START"
        workflow_progress = 0
        workflow_stage = "0 / 4  SAFETY-GATES GESPERRT"
    else:
        return unavailable
    return {
        "configured": configured,
        "action_allowed": action_allowed,
        "request_allowed": True,
        "request_result": "",
        "state": state,
        "tone": tone,
        "headline": _safe_text(headline, 48),
        "detail": _safe_text(detail, 96),
        "button": _safe_text(button, 32),
        "review": _safe_text(review_text, 96),
        # This is workflow progress, not an estimate of physical trajectory
        # completion.  The backend currently exposes only bounded ownership
        # states, so the UI must not invent robot-position telemetry.
        "workflow_progress": workflow_progress,
        "workflow_stage": _safe_text(workflow_stage, 48),
        "stop_allowed": state in ("armed_live", "fault_locked"),
    }


def _safety_vector(value, length, minimum, maximum):
    if not isinstance(value, (list, tuple)) or len(value) != length:
        return None
    result = []
    for item in value:
        if isinstance(item, bool) or not isinstance(item, (int, float)):
            return None
        number = float(item)
        if number != number or not minimum <= number <= maximum:
            return None
        result.append(number)
    return result


def _safety_number(value, minimum, maximum):
    if isinstance(value, bool) or not isinstance(value, (int, float)):
        return None
    result = float(value)
    if result != result or not minimum <= result <= maximum:
        return None
    return result


def _safety_configuration_view(view):
    """Reduce only a pinned profile and its exact controller readback."""

    view = _mapping(view)
    xarm = _mapping(view.get("xarm"))
    raw = _mapping(xarm.get("safety_configurator"))
    unavailable = {
        "valid": False,
        "state": "unavailable",
        "tone": "muted",
        "headline": "SAFETY-PROFIL NICHT VERFUEGBAR",
        "detail": "Backend-Profil und Controller-Readback fehlen",
        "profile_sha256": "--",
        "digest_short": "--",
        "profile_rows": (),
        "preflight_rows": (),
        "configured": False,
        "exact_readback": False,
        "action_allowed": False,
        "button": "NICHT VERFUEGBAR",
        "search_ready": False,
        "remaining_gates": ("Authoritativer Backend-Status fehlt",),
        "last_error": "",
    }
    states = (
        "unavailable",
        "requires_configuration",
        "ready_to_configure",
        "configuring",
        "configured",
        "unsafe",
        "error",
    )
    if raw.get("schema_version") != 1 or raw.get("state") not in states:
        return unavailable
    for name in ("capable", "profile_loaded", "configured", "search_admission_ready"):
        if not isinstance(raw.get(name), bool):
            return unavailable
    last_error = raw.get("last_error")
    if (
        not isinstance(last_error, str)
        or len(last_error) > 48
        or any(ord(character) < 32 or ord(character) > 126 for character in last_error)
    ):
        return unavailable
    raw_remaining = raw.get("remaining_search_gates")
    known_gate_labels = {
        "motion_release_incomplete": "Formale Bewegungsfreigabe fehlt",
        "safety_boundary_configuration": "TCP-Grenzprofil + Readback",
        "operator_deployment": "Operator Deployment",
        "reviewed_motion_owner": "Gepruefter Search Path / Motion Owner",
        "services_started": "Backend Services",
        "xarm_healthy": "xArm fehlerfrei",
        "xarm_telemetry_fresh": "xArm Telemetrie frisch",
        "xarm_stationary": "xArm Stillstand",
        "reduced_mode": "Reduced Mode",
        "reduced_configuration": "Reduced-Konfiguration",
        "joint_envelope": "Joint Envelope",
        "control_envelope": "TCP Control Envelope",
        "physical_operation_active": "Physischer Betrieb aktiv",
    }
    if not isinstance(raw_remaining, (list, tuple)):
        return unavailable
    if len(raw_remaining) > len(known_gate_labels):
        return unavailable
    remaining_ids = []
    unknown_remaining = False
    for gate in raw_remaining:
        if not isinstance(gate, str) or gate not in known_gate_labels:
            unknown_remaining = True
        else:
            if gate in remaining_ids:
                return unavailable
            remaining_ids.append(gate)
    digest = raw.get("profile_sha256")
    if raw.get("profile_loaded") is True and not _lower_hex(digest, 64):
        return unavailable
    profile = _mapping(raw.get("profile"))
    readback = _mapping(raw.get("readback"))
    preflight = _mapping(raw.get("preflight"))
    preflight_names = (
        "ready",
        "connected",
        "healthy",
        "stopped",
        "motors_disabled",
        "stationary",
        "identity_verified",
        "mode_locked",
        "brakes_engaged",
        "pose_inside_profile",
        "controller_binding_verified",
    )
    if any(not isinstance(preflight.get(name), bool) for name in preflight_names):
        return unavailable
    if preflight.get("ready") is True and any(
        preflight.get(name) is not True for name in preflight_names[1:]
    ):
        return unavailable

    boundary = _safety_vector(profile.get("tcp_boundary_mm"), 6, -1000000.0, 1000000.0)
    joints = _safety_vector(profile.get("joint_ranges_radians"), 14, -1000.0, 1000.0)
    tcp_speed = _safety_number(
        profile.get("max_tcp_speed_mm_per_second"), 0.001, 1000000.0
    )
    joint_speed = _safety_number(
        profile.get("max_joint_speed_radians_per_second"), 0.000001, 1000.0
    )
    profile_fixed = bool(
        profile.get("safety_boundary_enabled") is True
        and profile.get("collision_rebound_enabled") is False
        and profile.get("reduced_mode_enabled") is True
    )
    if raw.get("profile_loaded") is True and (
        boundary is None
        or joints is None
        or any(boundary[index * 2] <= boundary[index * 2 + 1] for index in range(3))
        or any(joints[index * 2] >= joints[index * 2 + 1] for index in range(6))
        or joints[12:] != [0.0, 0.0]
        or tcp_speed is None
        or joint_speed is None
        or not profile_fixed
    ):
        return unavailable

    rb_boundary = _safety_vector(
        readback.get("tcp_boundary_mm"), 6, -1000000.0, 1000000.0
    )
    rb_joints = _safety_vector(
        readback.get("joint_ranges_radians"), 14, -1000.0, 1000.0
    )
    rb_tcp_speed = _safety_number(
        readback.get("max_tcp_speed_mm_per_second"), 0.001, 1000000.0
    )
    rb_joint_speed = _safety_number(
        readback.get("max_joint_speed_radians_per_second"), 0.000001, 1000.0
    )
    if not isinstance(readback.get("verified"), bool):
        return unavailable
    if readback.get("verified") is True and raw.get("configured") is not True:
        return unavailable
    for name in (
        "safety_boundary_enabled",
        "reduced_mode_enabled",
        "collision_rebound_enabled",
    ):
        if not isinstance(readback.get(name), bool):
            return unavailable
    exact = bool(
        raw.get("configured") is True
        and raw.get("state") == "configured"
        and readback.get("verified") is True
        and boundary is not None
        and boundary == rb_boundary
        and joints == rb_joints
        and tcp_speed == rb_tcp_speed
        and joint_speed == rb_joint_speed
        and readback.get("safety_boundary_enabled") is True
        and readback.get("reduced_mode_enabled") is True
        and readback.get("collision_rebound_enabled") is False
    )
    if raw.get("configured") is True and not exact:
        return dict(
            unavailable,
            valid=True,
            state="unsafe",
            tone="danger",
            headline="READBACK STIMMT NICHT UEBEREIN",
            detail="Controller bleibt fuer Search gesperrt",
            profile_sha256=digest,
            digest_short=digest[:16] if _lower_hex(digest, 64) else "--",
            last_error="readback_mismatch",
        )

    profile_rows = []
    if boundary is not None and joints is not None:
        profile_rows.extend(
            (
                ("X MIN / MAX", "%.1f / %.1f MM" % (boundary[1], boundary[0])),
                ("Y MIN / MAX", "%.1f / %.1f MM" % (boundary[3], boundary[2])),
                ("Z MIN / MAX", "%.1f / %.1f MM" % (boundary[5], boundary[4])),
                ("TCP MAX", "%.1f MM/S" % tcp_speed),
                ("JOINT MAX", "%.1f DEG/S" % (joint_speed * 57.295779513)),
            )
        )
        for index in range(6):
            profile_rows.append(
                (
                    "J%d MIN / MAX" % (index + 1),
                    "%.1f / %.1f DEG"
                    % (
                        joints[index * 2] * 57.295779513,
                        joints[index * 2 + 1] * 57.295779513,
                    ),
                )
            )
        profile_rows.extend(
            (
                ("REDUCED MODE", "EIN"),
                ("TCP-SICHERHEITSGRENZE", "EIN"),
                ("KOLLISIONS-RUECKFEDERUNG", "AUS"),
            )
        )
    preflight_labels = (
        ("connected", "CONTROLLER VERBUNDEN"),
        ("healthy", "FEHLERFREI"),
        ("stopped", "CONTROLLER VERRIEGELT"),
        ("motors_disabled", "MOTOREN AUS"),
        ("stationary", "ROBOTER STEHT"),
        ("identity_verified", "LITE6 IDENTITAET"),
        ("mode_locked", "MODE VERRIEGELT"),
        ("brakes_engaged", "BREMSEN EINGELEGT"),
        ("pose_inside_profile", "TCP + JOINTS IM PROFIL"),
        ("controller_binding_verified", "CONTROLLER-BINDUNG"),
    )
    preflight_rows = tuple(
        (label, "OK" if preflight.get(name) is True else "FEHLT")
        for name, label in preflight_labels
    )

    search = _motion_search_view(view)
    search_ready = bool(
        exact
        and preflight.get("ready") is True
        and raw.get("search_admission_ready") is True
        and search.get("action_allowed") is True
        and not last_error
        and xarm.get("system_check_ok") is True
        and xarm.get("motion_ready") is True
        and xarm.get("moving") is False
    )
    remaining = [known_gate_labels[gate] for gate in remaining_ids]
    if unknown_remaining:
        remaining.append("Unbekanntes Backend-Gate (Search gesperrt)")
    if not remaining and not search_ready:
        remaining.append("Separaten Search-Backend-Check abwarten")
    search_ready = bool(search_ready and not unknown_remaining and not remaining_ids)

    state = raw.get("state")
    operation_active = "physical_operation_active" in remaining_ids
    if exact:
        headline = "CONTROLLER-GRENZEN GEPRUEFT"
        detail = (
            "PINNED = CONTROLLER-READBACK / Search Path separat startbereit"
            if search_ready
            else "PINNED = CONTROLLER-READBACK; weitere Search-Gates gesperrt"
        )
        tone = "ok" if search_ready else "warn"
        button = "ZUR SEARCH-FUNKTION" if search_ready else "READBACK GEPRUEFT"
    elif state == "ready_to_configure" and preflight.get("ready") is True:
        headline = "PINNED SAFETY-PROFIL BEREIT"
        detail = "Controller wird verriegelt; Motoren bleiben aus; keine Bewegung"
        tone = "warn"
        button = "KONFIGURATION PRUEFEN"
    elif state == "configuring":
        headline = "CONTROLLER-READBACK WIRD GEPRUEFT"
        detail = "Search bleibt bis zum exakten Readback gesperrt"
        tone = "warn"
        button = "BITTE WARTEN"
    elif operation_active:
        headline = "PHYSISCHER BETRIEB AKTIV"
        detail = "Safety-Setup wartet, bis der laufende Betrieb beendet ist"
        tone = "warn"
        button = "BETRIEB AKTIV"
    elif state in ("unsafe", "error"):
        headline = "SAFETY-KONFIGURATION GESPERRT"
        detail = "Preflight oder Controller-Readback ist nicht sicher"
        tone = "danger"
        button = "ERNEUT PRUEFEN"
    else:
        headline = "SAFETY-SETUP ERFORDERLICH"
        detail = "Preflight muss Motoren AUS und Stillstand bestaetigen"
        tone = "warn"
        button = "SAFETY-PROFIL PRUEFEN"
    action_allowed = bool(
        raw.get("capable") is True
        and raw.get("profile_loaded") is True
        and preflight.get("ready") is True
        and not unknown_remaining
        and not operation_active
        and not exact
        and state in ("requires_configuration", "ready_to_configure", "unsafe", "error")
    )
    return {
        "valid": True,
        "state": state,
        "tone": tone,
        "headline": headline,
        "detail": detail,
        "profile_sha256": digest if _lower_hex(digest, 64) else "--",
        "digest_short": digest[:16] if _lower_hex(digest, 64) else "--",
        "profile_rows": tuple(profile_rows),
        "preflight_rows": preflight_rows,
        "configured": exact,
        "exact_readback": exact,
        "action_allowed": action_allowed,
        "button": button,
        "search_ready": search_ready,
        "remaining_gates": tuple(remaining),
        "last_error": _safe_text(last_error, 48),
    }


def _bounded_count(value, maximum=1_000_000_000):
    if isinstance(value, bool) or not isinstance(value, int):
        return 0
    return min(max(value, 0), maximum)


def _bounded_number(value, minimum=0.0, maximum=1e12):
    if isinstance(value, bool) or not isinstance(value, (int, float)):
        return None
    if value != value or value < minimum or value > maximum:
        return None
    return value


_DIGITAL_TWIN_TOP_KEYS = (
    "schema_version",
    "configured",
    "state",
    "coordinate_frame",
    "model_sha256",
    "sample_age_seconds",
    "pose_sequence",
    "joint_angles_rad",
    "link_points_mm",
    "tcp_pose_mm_rad",
    "workspace_bounds_mm",
    "cameras",
    "scene",
    "plan",
    "gates",
)
_DIGITAL_TWIN_STATES = (
    "unavailable",
    "blocked",
    "ready",
    "active",
)
_DIGITAL_TWIN_PLAN_STATES = (
    "unavailable",
    "none",
    "planned",
    "validated",
    "active",
    "failed",
)
_DIGITAL_TWIN_BLOCKERS = (
    "no_xarm_telemetry",
    "stale_pose",
    "invalid_joint_vector",
    "model_tcp_mismatch",
    "tool_depth_unavailable",
    "workspace_depth_unavailable",
    "tool_depth_calibration_missing",
    "workspace_depth_calibration_missing",
    "dual_depth_stale",
    "dual_depth_skew",
    "tool_pose_skew",
    "depth_sequence_mismatch",
    "unknown_swept_volume",
    "camera_disagreement",
    "clearance_below_limit",
    "trajectory_unavailable",
    "motion_release_incomplete",
)
_DIGITAL_TWIN_GATE_KEYS = (
    "pose_fresh",
    "pair_synchronized",
    "calibrations_verified",
    "model_verified",
    "coverage_verified",
    "trajectory_valid",
    "clearance_verified",
    "motion_release_valid",
    "admission_ready",
    "blockers",
)


def _strict_twin_number(value, minimum, maximum):
    """Return one finite number without accepting bool or coercing strings."""

    if isinstance(value, bool) or not isinstance(value, (int, float)):
        return None
    if value != value or value < minimum or value > maximum:
        return None
    return float(value)


def _strict_twin_integer(value, maximum):
    if (
        isinstance(value, bool)
        or not isinstance(value, int)
        or value < 0
        or value > maximum
    ):
        return None
    return value


def _strict_twin_vector(value, length, minimum, maximum):
    if not isinstance(value, (list, tuple)) or len(value) != length:
        return None
    result = []
    for item in value:
        number = _strict_twin_number(item, minimum, maximum)
        if number is None:
            return None
        result.append(number)
    return tuple(result)


def _strict_twin_point_list(value, minimum_count, maximum_count):
    if (
        not isinstance(value, (list, tuple))
        or len(value) < minimum_count
        or len(value) > maximum_count
    ):
        return None
    result = []
    for item in value:
        point = _strict_twin_vector(item, 3, -1_000_000.0, 1_000_000.0)
        if point is None:
            return None
        result.append(point)
    return tuple(result)


def _strict_twin_source_id(value):
    if not isinstance(value, str) or len(value) > 255:
        return None
    if any(not 32 <= ord(character) <= 126 for character in value):
        return None
    return _safe_text(value, 96)


def _digital_twin_unavailable(reason="contract unavailable", dangerous=False):
    gate_rows = (
        ("POSE", False),
        ("DUAL CAM SYNC", False),
        ("CALIBRATION", False),
        ("ROBOT MODEL", False),
        ("COVERAGE", False),
        ("TRAJECTORY", False),
        ("CLEARANCE", False),
        ("MOTION RELEASE", False),
    )
    gates = dict((name, False) for name in _DIGITAL_TWIN_GATE_KEYS[:-1])
    gates["blockers"] = ("digital_twin_contract_invalid",)
    return {
        "valid": False,
        "configured": False,
        "state": "unavailable",
        "tone": "danger" if dangerous else "muted",
        "headline": (
            "DIGITAL TWIN CONTRACT ERROR" if dangerous else "DIGITAL TWIN UNAVAILABLE"
        ),
        "detail": _safe_text(reason, 96),
        "status": "ERROR" if dangerous else "UNAVAILABLE",
        "coordinate_frame": "--",
        "model_sha256": "--",
        "model_digest": "--",
        "sample_age_seconds": None,
        "pose_sequence": None,
        "joint_angles_rad": (),
        "link_points_mm": (),
        "tcp_pose_mm_rad": (),
        "workspace_bounds_mm": {"lower": (), "upper": ()},
        "cameras": {
            "tool": {
                "source_id": "--",
                "frame_sequence": None,
                "age_seconds": None,
                "depth_ready": False,
                "calibration_sha256": "--",
            },
            "workspace": {
                "source_id": "--",
                "frame_sequence": None,
                "age_seconds": None,
                "depth_ready": False,
                "calibration_sha256": "--",
            },
        },
        "scene": {
            "scene_sha256": "--",
            "pair_skew_seconds": None,
            "coverage_ratio": None,
            "nearest_obstacle_mm": None,
            "current_clearance_mm": None,
            "planned_min_clearance_mm": None,
            "required_clearance_mm": None,
            "swept_volume_clear": False,
        },
        "plan": {
            "state": "unavailable",
            "plan_sha256": "--",
            "waypoint_count": 0,
            "tcp_path_mm": (),
        },
        "gates": gates,
        "blockers": ("digital_twin_contract_invalid",),
        "gate_rows": gate_rows,
        "preflight_ready": False,
        "admission_ready": False,
        "render_ready": False,
    }


def _digital_twin_view(runtime):
    """Strictly reduce the bounded, read-only dual-camera 3D twin contract.

    This reducer intentionally has no permissive/legacy branch.  One wrong
    key, type, count, digest, coordinate, or cross-field safety claim makes
    the complete twin unavailable and can never create motion permission.
    """

    raw_runtime = _mapping(runtime)
    raw_value = raw_runtime.get("digital_twin")
    if raw_value is None:
        return _digital_twin_unavailable()
    if not isinstance(raw_value, dict):
        return _digital_twin_unavailable("digital twin is not an object", True)
    raw = raw_value
    if set(raw) != set(_DIGITAL_TWIN_TOP_KEYS):
        return _digital_twin_unavailable("digital twin keys do not match v1", True)
    if raw.get("schema_version") != 1 or isinstance(raw.get("schema_version"), bool):
        return _digital_twin_unavailable("digital twin schema is not v1", True)
    if raw.get("configured") is not True:
        return _digital_twin_unavailable("digital twin is not configured")

    state = raw.get("state")
    if state not in _DIGITAL_TWIN_STATES:
        return _digital_twin_unavailable("digital twin state is invalid", True)
    if raw.get("coordinate_frame") != "xarm_base_mm":
        return _digital_twin_unavailable("coordinate frame is not xarm_base_mm", True)
    model_digest = raw.get("model_sha256")
    if not _lower_hex(model_digest, 64):
        return _digital_twin_unavailable("robot model digest is invalid", True)
    sample_age = _strict_twin_number(raw.get("sample_age_seconds"), 0.0, 86400.0)
    pose_sequence = _strict_twin_integer(raw.get("pose_sequence"), 10_000_000_000)
    joint_angles = _strict_twin_vector(raw.get("joint_angles_rad"), 6, -1000.0, 1000.0)
    link_points = _strict_twin_point_list(raw.get("link_points_mm"), 7, 7)
    tcp_pose = _strict_twin_vector(
        raw.get("tcp_pose_mm_rad"), 6, -1_000_000.0, 1_000_000.0
    )
    if sample_age is None or pose_sequence is None or joint_angles is None:
        return _digital_twin_unavailable("robot pose sample is malformed", True)
    if link_points is None or tcp_pose is None:
        return _digital_twin_unavailable("robot geometry is malformed", True)
    if any(abs(value) > 1000.0 for value in tcp_pose[3:]):
        return _digital_twin_unavailable("TCP orientation is outside bounds", True)

    raw_bounds = raw.get("workspace_bounds_mm")
    if not isinstance(raw_bounds, dict) or set(raw_bounds) != {"lower", "upper"}:
        return _digital_twin_unavailable("workspace bounds are malformed", True)
    lower = _strict_twin_vector(raw_bounds.get("lower"), 3, -1_000_000.0, 1_000_000.0)
    upper = _strict_twin_vector(raw_bounds.get("upper"), 3, -1_000_000.0, 1_000_000.0)
    if (
        lower is None
        or upper is None
        or any(lower[index] >= upper[index] for index in range(3))
    ):
        return _digital_twin_unavailable("workspace bounds are invalid", True)

    raw_cameras = raw.get("cameras")
    camera_keys = {
        "source_id",
        "frame_sequence",
        "age_seconds",
        "depth_ready",
        "calibration_sha256",
    }
    if not isinstance(raw_cameras, dict) or set(raw_cameras) != {
        "tool",
        "workspace",
    }:
        return _digital_twin_unavailable("dual-camera contract is malformed", True)
    cameras = {}
    for role in ("tool", "workspace"):
        camera = raw_cameras.get(role)
        if not isinstance(camera, dict) or set(camera) != camera_keys:
            return _digital_twin_unavailable("camera keys do not match v1", True)
        source_id = _strict_twin_source_id(camera.get("source_id"))
        frame_sequence = _strict_twin_integer(
            camera.get("frame_sequence"), 10_000_000_000
        )
        calibration_digest = camera.get("calibration_sha256")
        depth_ready_value = camera.get("depth_ready")
        age_raw = camera.get("age_seconds")
        age_seconds = (
            None if age_raw is None else _strict_twin_number(age_raw, 0.0, 86400.0)
        )
        calibration_empty = calibration_digest in (None, "")
        if (
            source_id is None
            or frame_sequence is None
            or not isinstance(depth_ready_value, bool)
            or (age_raw is not None and age_seconds is None)
            or (not calibration_empty and not _lower_hex(calibration_digest, 64))
            or (
                depth_ready_value is True
                and (age_seconds is None or not _lower_hex(calibration_digest, 64))
            )
        ):
            return _digital_twin_unavailable("camera sample is malformed", True)
        cameras[role] = {
            "source_id": source_id,
            "frame_sequence": frame_sequence,
            "age_seconds": age_seconds,
            "depth_ready": depth_ready_value is True,
            "calibration_sha256": (
                calibration_digest if _lower_hex(calibration_digest, 64) else ""
            ),
        }

    raw_scene = raw.get("scene")
    scene_keys = {
        "scene_sha256",
        "pair_skew_seconds",
        "coverage_ratio",
        "nearest_obstacle_mm",
        "current_clearance_mm",
        "planned_min_clearance_mm",
        "required_clearance_mm",
        "swept_volume_clear",
    }
    if not isinstance(raw_scene, dict) or set(raw_scene) != scene_keys:
        return _digital_twin_unavailable("3D scene keys do not match v1", True)
    scene_digest = raw_scene.get("scene_sha256")
    pair_skew_raw = raw_scene.get("pair_skew_seconds")
    pair_skew = (
        None if pair_skew_raw is None else _strict_twin_number(pair_skew_raw, 0.0, 60.0)
    )
    coverage = _strict_twin_number(raw_scene.get("coverage_ratio"), 0.0, 1.0)
    nearest_raw = raw_scene.get("nearest_obstacle_mm")
    nearest = (
        None
        if nearest_raw is None
        else _strict_twin_number(nearest_raw, 0.0, 1_000_000.0)
    )

    def optional_clearance(name):
        value = raw_scene.get(name)
        if value is None:
            return None
        return _strict_twin_number(value, 0.0, 1_000_000.0)

    current_clearance = optional_clearance("current_clearance_mm")
    planned_clearance = optional_clearance("planned_min_clearance_mm")
    required_clearance = _strict_twin_number(
        raw_scene.get("required_clearance_mm"), 0.0, 100_000.0
    )
    if (
        (
            not isinstance(scene_digest, str)
            or (scene_digest != "" and not _lower_hex(scene_digest, 64))
        )
        or (pair_skew_raw is not None and pair_skew is None)
        or (
            coverage is None
            or (nearest_raw is not None and nearest is None)
            or (
                raw_scene.get("current_clearance_mm") is not None
                and current_clearance is None
            )
            or (
                raw_scene.get("planned_min_clearance_mm") is not None
                and planned_clearance is None
            )
            or required_clearance is None
            or not isinstance(raw_scene.get("swept_volume_clear"), bool)
        )
    ):
        return _digital_twin_unavailable("3D scene values are malformed", True)

    raw_plan = raw.get("plan")
    plan_keys = {"state", "plan_sha256", "waypoint_count", "tcp_path_mm"}
    if not isinstance(raw_plan, dict) or set(raw_plan) != plan_keys:
        return _digital_twin_unavailable("trajectory keys do not match v1", True)
    plan_state = raw_plan.get("state")
    plan_digest = raw_plan.get("plan_sha256")
    waypoint_count = _strict_twin_integer(raw_plan.get("waypoint_count"), 1_000_000)
    path = _strict_twin_point_list(raw_plan.get("tcp_path_mm"), 0, 32)
    if (
        plan_state not in _DIGITAL_TWIN_PLAN_STATES
        or waypoint_count is None
        or path is None
        or waypoint_count < len(path)
        or (plan_digest != "" and not _lower_hex(plan_digest, 64))
    ):
        return _digital_twin_unavailable("trajectory values are malformed", True)
    if plan_state in ("validated", "active") and (
        not _lower_hex(plan_digest, 64) or waypoint_count < 1 or len(path) < 1
    ):
        return _digital_twin_unavailable("validated trajectory has no evidence", True)
    if waypoint_count == 0 and path:
        return _digital_twin_unavailable("empty trajectory contains points", True)

    raw_gates = raw.get("gates")
    if not isinstance(raw_gates, dict) or set(raw_gates) != set(
        _DIGITAL_TWIN_GATE_KEYS
    ):
        return _digital_twin_unavailable("safety gate keys do not match v1", True)
    gates = {}
    for key in _DIGITAL_TWIN_GATE_KEYS[:-1]:
        value = raw_gates.get(key)
        if not isinstance(value, bool):
            return _digital_twin_unavailable("safety gate value is malformed", True)
        gates[key] = value is True
    raw_blockers = raw_gates.get("blockers")
    if (
        not isinstance(raw_blockers, (list, tuple))
        or len(raw_blockers) > 16
        or any(not isinstance(item, str) for item in raw_blockers)
        or len(set(raw_blockers)) != len(raw_blockers)
        or any(item not in _DIGITAL_TWIN_BLOCKERS for item in raw_blockers)
    ):
        return _digital_twin_unavailable("safety blocker list is malformed", True)
    blockers = tuple(raw_blockers)

    scene_digest_valid = _lower_hex(scene_digest, 64)
    if (
        gates["pair_synchronized"]
        or gates["coverage_verified"]
        or gates["trajectory_valid"]
        or gates["clearance_verified"]
    ) and not scene_digest_valid:
        return _digital_twin_unavailable("scene evidence digest is missing", True)
    if gates["pair_synchronized"] and pair_skew is None:
        return _digital_twin_unavailable("camera-pair skew evidence is missing", True)
    if gates["clearance_verified"] and (
        current_clearance is None
        or planned_clearance is None
        or required_clearance <= 0.0
    ):
        return _digital_twin_unavailable("clearance evidence is missing", True)

    def point_inside(point):
        return all(lower[index] <= point[index] <= upper[index] for index in range(3))

    # The box is a TCP/search boundary, not a volume that must contain the
    # robot base or every link. Only planned TCP points claim box admission.
    if any(not point_inside(point) for point in path):
        return _digital_twin_unavailable("TCP path leaves the declared workspace", True)
    depth_ready = all(cameras[role]["depth_ready"] for role in cameras)
    clearances_safe = bool(
        current_clearance is not None
        and planned_clearance is not None
        and required_clearance > 0.0
        and current_clearance >= required_clearance
        and planned_clearance >= required_clearance
        and raw_scene.get("swept_volume_clear") is True
    )
    non_release_blockers = tuple(
        item for item in blockers if item != "motion_release_incomplete"
    )
    preflight_ready = bool(
        gates["pose_fresh"]
        and gates["pair_synchronized"]
        and gates["calibrations_verified"]
        and gates["model_verified"]
        and gates["coverage_verified"]
        and gates["trajectory_valid"]
        and gates["clearance_verified"]
        and depth_ready
        and clearances_safe
        and plan_state == "validated"
        and not non_release_blockers
    )
    derived_admission = bool(
        preflight_ready
        and gates["motion_release_valid"]
        and not blockers
        and state == "ready"
    )
    if gates["admission_ready"] is True and not derived_admission:
        return _digital_twin_unavailable("unsafe admission claim was rejected", True)
    if state == "ready" and gates["admission_ready"] is not True:
        return _digital_twin_unavailable("ready state lacks admission evidence", True)
    if state == "active" and plan_state != "active":
        return _digital_twin_unavailable("active state lacks active trajectory", True)
    admission_ready = gates["admission_ready"] is True and derived_admission

    gate_rows = (
        ("POSE", gates["pose_fresh"]),
        ("DUAL CAM SYNC", gates["pair_synchronized"] and depth_ready),
        ("CALIBRATION", gates["calibrations_verified"]),
        ("ROBOT MODEL", gates["model_verified"]),
        ("COVERAGE", gates["coverage_verified"]),
        ("TRAJECTORY", gates["trajectory_valid"]),
        ("CLEARANCE", gates["clearance_verified"] and clearances_safe),
        ("MOTION RELEASE", gates["motion_release_valid"]),
    )
    state_labels = {
        "unavailable": ("DIGITAL TWIN UNAVAILABLE", "warn", "UNAVAILABLE"),
        "blocked": ("SEARCH TRAJECTORY BLOCKED", "warn", "BLOCKED"),
        "ready": ("3D SEARCH TRAJECTORY CLEAR", "ok", "READY"),
        "active": ("SEARCH TRAJECTORY ACTIVE", "danger", "ACTIVE"),
    }
    headline, tone, status = state_labels[state]
    if preflight_ready and not admission_ready and state == "blocked":
        status = "GATES OK"
    clearance_text = (
        "CLEARANCE -- / REQUIRED %.1f MM" % required_clearance
        if planned_clearance is None
        else "PLAN %.1f MM / REQUIRED %.1f MM" % (planned_clearance, required_clearance)
    )
    blocker_text = blockers[0].replace("_", " ").upper() if blockers else "NO BLOCKERS"
    detail = "%s | %s" % (clearance_text, blocker_text)
    scene = {
        "scene_sha256": scene_digest if scene_digest_valid else "",
        "pair_skew_seconds": pair_skew,
        "coverage_ratio": coverage,
        "nearest_obstacle_mm": nearest,
        "current_clearance_mm": current_clearance,
        "planned_min_clearance_mm": planned_clearance,
        "required_clearance_mm": required_clearance,
        "swept_volume_clear": raw_scene.get("swept_volume_clear") is True,
    }
    plan = {
        "state": plan_state,
        "plan_sha256": plan_digest or "--",
        "waypoint_count": waypoint_count,
        "tcp_path_mm": path,
    }
    result_gates = dict(gates)
    result_gates["blockers"] = blockers
    return {
        "valid": True,
        "configured": True,
        "state": state,
        "tone": tone,
        "headline": headline,
        "detail": _safe_text(detail, 96),
        "status": status,
        "coordinate_frame": "xarm_base_mm",
        "model_sha256": model_digest,
        "model_digest": model_digest[:12],
        "sample_age_seconds": sample_age,
        "pose_sequence": pose_sequence,
        "joint_angles_rad": joint_angles,
        "link_points_mm": link_points,
        "tcp_pose_mm_rad": tcp_pose,
        "workspace_bounds_mm": {"lower": lower, "upper": upper},
        "cameras": cameras,
        "scene": scene,
        "plan": plan,
        "gates": result_gates,
        "blockers": blockers,
        "gate_rows": gate_rows,
        "preflight_ready": preflight_ready,
        "admission_ready": admission_ready,
        "render_ready": True,
    }


def _project_digital_twin_geometry(twin, projection, width, height):
    """Project validated millimetre geometry into one bounded LVGL viewport."""

    twin = _mapping(twin)
    if twin.get("valid") is not True or projection not in (
        "isometric",
        "top",
        "front",
    ):
        return {"valid": False, "workspace_edges": (), "arm": (), "path": ()}
    if (
        isinstance(width, bool)
        or isinstance(height, bool)
        or not isinstance(width, int)
        or not isinstance(height, int)
        or not 64 <= width <= 4096
        or not 64 <= height <= 4096
    ):
        return {"valid": False, "workspace_edges": (), "arm": (), "path": ()}
    bounds = _mapping(twin.get("workspace_bounds_mm"))
    lower = bounds.get("lower")
    upper = bounds.get("upper")
    if not (
        isinstance(lower, (list, tuple))
        and isinstance(upper, (list, tuple))
        and len(lower) == 3
        and len(upper) == 3
    ):
        return {"valid": False, "workspace_edges": (), "arm": (), "path": ()}

    def project(point):
        x, y, z = point
        if projection == "top":
            return x, -y
        if projection == "front":
            return x, -z
        return (
            (x - y) * 0.70710678,
            ((x + y) * 0.40824829) - (z * 0.81649658),
        )

    lx, ly, lz = lower
    ux, uy, uz = upper
    corners = (
        (lx, ly, lz),
        (ux, ly, lz),
        (ux, uy, lz),
        (lx, uy, lz),
        (lx, ly, uz),
        (ux, ly, uz),
        (ux, uy, uz),
        (lx, uy, uz),
    )
    projected_corners = tuple(project(point) for point in corners)
    # Workspace bounds describe the TCP search box. Robot links may naturally
    # sit outside it, so fit the fixed view to the union without implying that
    # the box is a link-volume envelope.
    extent_points = list(projected_corners)
    extent_points.extend(project(point) for point in twin.get("link_points_mm", ()))
    minimum_u = min(point[0] for point in extent_points)
    maximum_u = max(point[0] for point in extent_points)
    minimum_v = min(point[1] for point in extent_points)
    maximum_v = max(point[1] for point in extent_points)
    span_u = maximum_u - minimum_u
    span_v = maximum_v - minimum_v
    if span_u <= 0.0 or span_v <= 0.0:
        return {"valid": False, "workspace_edges": (), "arm": (), "path": ()}
    padding = max(10, min(28, min(width, height) // 12))
    available_width = width - (padding * 2)
    available_height = height - (padding * 2)
    if available_width <= 0 or available_height <= 0:
        return {"valid": False, "workspace_edges": (), "arm": (), "path": ()}
    scale = min(available_width / span_u, available_height / span_v)
    used_width = span_u * scale
    used_height = span_v * scale
    offset_x = padding + ((available_width - used_width) / 2.0)
    offset_y = padding + ((available_height - used_height) / 2.0)

    def pixel(point):
        u, v = project(point)
        x = int(round(offset_x + ((u - minimum_u) * scale)))
        y = int(round(offset_y + ((v - minimum_v) * scale)))
        return (
            min(max(x, 0), width - 1),
            min(max(y, 0), height - 1),
        )

    pixel_corners = tuple(pixel(point) for point in corners)
    edge_indexes = (
        (0, 1),
        (1, 2),
        (2, 3),
        (3, 0),
        (4, 5),
        (5, 6),
        (6, 7),
        (7, 4),
        (0, 4),
        (1, 5),
        (2, 6),
        (3, 7),
    )
    workspace_edges = tuple(
        (pixel_corners[first], pixel_corners[second]) for first, second in edge_indexes
    )
    arm = tuple(pixel(point) for point in twin.get("link_points_mm", ()))
    path = tuple(
        pixel(point) for point in _mapping(twin.get("plan")).get("tcp_path_mm", ())
    )
    return {
        "valid": len(arm) == 7,
        "workspace_edges": workspace_edges,
        "arm": arm,
        "path": path,
        # v1 exposes only a scalar nearest-obstacle distance.  A marker would
        # invent a direction, so no obstacle position is projected.
        "obstacle": None,
    }


_WORKSPACE_TEACH_KEYS = (
    "schema_version",
    "configured",
    "state",
    "coordinate_frame",
    "required_controller_mode",
    "session_id",
    "current_step",
    "completed_steps",
    "total_steps",
    "guidance",
    "pose_ready",
    "current_tcp_position_mm",
    "hard_envelope_mm",
    "captured_bounds_mm",
    "proposal_sha256",
    "blockers",
    "safety_notice",
)
_WORKSPACE_TEACH_STATES = (
    "idle",
    "awaiting_teach",
    "positioning",
    "ready_to_capture",
    "review",
    "proposed",
    "cancelled",
    "invalidated",
)
_WORKSPACE_TEACH_STEPS = (
    "x_min",
    "x_max",
    "y_min",
    "y_max",
    "z_min",
    "z_max",
)
_WORKSPACE_TEACH_BLOCKERS = (
    "session_not_started",
    "session_finished",
    "telemetry_unavailable",
    "telemetry_stale",
    "xarm_disconnected",
    "xarm_fault",
    "wrong_robot",
    "teach_mode_not_active",
    "controller_not_ready",
    "invalid_joint_vector",
    "invalid_tcp_pose",
    "pose_outside_hard_envelope",
    "robot_moving",
    "pose_sequence_invalid",
    "pose_reused",
    "pose_unstable",
    "insufficient_span",
    "session_invalidated",
)
_WORKSPACE_TEACH_GUIDANCE = {
    "x_min": {
        "axis": "x",
        "side": "min",
        "title": "LINKE X-GRENZE",
        "instruction": "TCP von Hand zur kleinsten erlaubten X-Position fuehren.",
    },
    "x_max": {
        "axis": "x",
        "side": "max",
        "title": "RECHTE X-GRENZE",
        "instruction": "TCP von Hand zur groessten erlaubten X-Position fuehren.",
    },
    "y_min": {
        "axis": "y",
        "side": "min",
        "title": "VORDERE Y-GRENZE",
        "instruction": "TCP von Hand zur kleinsten erlaubten Y-Position fuehren.",
    },
    "y_max": {
        "axis": "y",
        "side": "max",
        "title": "HINTERE Y-GRENZE",
        "instruction": "TCP von Hand zur groessten erlaubten Y-Position fuehren.",
    },
    "z_min": {
        "axis": "z",
        "side": "min",
        "title": "UNTERE Z-GRENZE",
        "instruction": "TCP von Hand zur kleinsten erlaubten Z-Position fuehren.",
    },
    "z_max": {
        "axis": "z",
        "side": "max",
        "title": "OBERE Z-GRENZE",
        "instruction": "TCP von Hand zur groessten erlaubten Z-Position fuehren.",
    },
}
_WORKSPACE_TEACH_SAFETY_NOTICE = (
    "TCP-BOX IST NUR EIN PRUEFVORSCHLAG; KEINE MOTION-FREIGABE"
)
_WORKSPACE_BOUNDARY_KEYS = (
    "schema_version",
    "configured",
    "state",
    "session_id",
    "proposal_sha256",
    "robot_sha256",
    "bounds_mm",
    "cameras",
    "camera_evidence_sha256",
    "newton_version",
    "newton_model_sha256",
    "newton_result_sha256",
    "blockers",
    "motion_authority",
    "motion_authorized",
)
_WORKSPACE_BOUNDARY_STATES = (
    "unavailable",
    "idle",
    "validating",
    "valid",
    "blocked",
    "invalidated",
)
_WORKSPACE_BOUNDARY_BLOCKERS = (
    "proposal_invalid",
    "dual_depth_unavailable",
    "dual_depth_blocked",
    "newton_unavailable",
    "newton_mismatch",
    "stopped",
    "result_invalid",
)


def _workspace_teach_unavailable(reason="workspace teach unavailable", dangerous=False):
    return {
        "valid": False,
        "configured": False,
        "state": "unavailable",
        "tone": "danger" if dangerous else "muted",
        "headline": (
            "WORKSPACE TEACH CONTRACT ERROR"
            if dangerous
            else "WORKSPACE TEACH UNAVAILABLE"
        ),
        "detail": _safe_text(reason, 96),
        "status": "ERROR" if dangerous else "UNAVAILABLE",
        "coordinate_frame": "--",
        "required_controller_mode": 2,
        "session_id": "",
        "current_step": "",
        "completed_steps": 0,
        "total_steps": 6,
        "guidance": {},
        "pose_ready": False,
        "current_tcp_position_mm": (),
        "hard_envelope_mm": {"lower": (), "upper": ()},
        "captured_bounds_mm": {"lower": (), "upper": ()},
        "proposal_sha256": "",
        "proposal_digest": "--",
        "blockers": ("workspace_teach_contract_invalid",),
        "mode_two_blocked": True,
        "render_ready": False,
    }


def _workspace_teach_view(runtime):
    """Strictly reduce the guided, read-only Lite6 teach snapshot."""

    raw_runtime = _mapping(runtime)
    raw_value = raw_runtime.get("workspace_teach")
    if raw_value is None:
        return _workspace_teach_unavailable()
    if not isinstance(raw_value, dict):
        return _workspace_teach_unavailable("teach snapshot is not an object", True)
    raw = raw_value
    if set(raw) != set(_WORKSPACE_TEACH_KEYS):
        return _workspace_teach_unavailable("teach keys do not match v1", True)
    if raw.get("schema_version") != 1 or isinstance(raw.get("schema_version"), bool):
        return _workspace_teach_unavailable("teach schema is not v1", True)
    if not isinstance(raw.get("configured"), bool):
        return _workspace_teach_unavailable("configured flag is malformed", True)
    if raw.get("configured") is not True:
        return _workspace_teach_unavailable("workspace teach is not configured")
    state = raw.get("state")
    if state not in _WORKSPACE_TEACH_STATES:
        return _workspace_teach_unavailable("teach state is invalid", True)
    if raw.get("coordinate_frame") != "xarm_base_mm":
        return _workspace_teach_unavailable("teach coordinate frame is invalid", True)
    mode = raw.get("required_controller_mode")
    if isinstance(mode, bool) or mode != 2:
        return _workspace_teach_unavailable("required controller mode is invalid", True)
    session_id = raw.get("session_id")
    if not isinstance(session_id, str):
        return _workspace_teach_unavailable("teach session id is malformed", True)
    if state == "idle":
        if session_id != "":
            return _workspace_teach_unavailable("idle teach session has an id", True)
    elif not _lower_hex(session_id, 32):
        return _workspace_teach_unavailable("teach session id is invalid", True)

    completed = raw.get("completed_steps")
    total = raw.get("total_steps")
    if (
        isinstance(completed, bool)
        or not isinstance(completed, int)
        or not 0 <= completed <= 6
        or isinstance(total, bool)
        or total != 6
    ):
        return _workspace_teach_unavailable("teach progress is malformed", True)
    current_step = raw.get("current_step")
    expected_step = _WORKSPACE_TEACH_STEPS[completed] if completed < 6 else ""
    active_step_state = state in (
        "awaiting_teach",
        "positioning",
        "ready_to_capture",
    )
    if current_step != (expected_step if active_step_state else ""):
        return _workspace_teach_unavailable("current teach step is inconsistent", True)
    guidance = raw.get("guidance")
    expected_guidance = _WORKSPACE_TEACH_GUIDANCE[current_step] if current_step else {}
    if not isinstance(guidance, dict) or guidance != expected_guidance:
        return _workspace_teach_unavailable("teach guidance is not canonical", True)
    pose_ready = raw.get("pose_ready")
    if not isinstance(pose_ready, bool) or pose_ready != (state == "ready_to_capture"):
        return _workspace_teach_unavailable("pose-ready claim is inconsistent", True)

    def exact_box(value, nullable=False):
        if not isinstance(value, dict) or set(value) != {"lower", "upper"}:
            return None
        values = []
        for name in ("lower", "upper"):
            raw_vector = value.get(name)
            if not isinstance(raw_vector, (list, tuple)) or len(raw_vector) != 3:
                return None
            vector = []
            for item in raw_vector:
                if nullable and item is None:
                    vector.append(None)
                    continue
                number = _strict_twin_number(item, -1_000_000.0, 1_000_000.0)
                if number is None:
                    return None
                vector.append(number)
            values.append(tuple(vector))
        return {"lower": values[0], "upper": values[1]}

    hard = exact_box(raw.get("hard_envelope_mm"))
    captured = exact_box(raw.get("captured_bounds_mm"), nullable=True)
    if (
        hard is None
        or captured is None
        or any(hard["lower"][index] >= hard["upper"][index] for index in range(3))
    ):
        return _workspace_teach_unavailable("teach workspace box is invalid", True)
    captured_sequence = (
        captured["lower"][0],
        captured["upper"][0],
        captured["lower"][1],
        captured["upper"][1],
        captured["lower"][2],
        captured["upper"][2],
    )
    for index, value in enumerate(captured_sequence):
        if (index < completed) != (value is not None):
            return _workspace_teach_unavailable(
                "captured extrema are inconsistent", True
            )
    for axis in range(3):
        lower_value = captured["lower"][axis]
        upper_value = captured["upper"][axis]
        if lower_value is not None and not (
            hard["lower"][axis] <= lower_value <= hard["upper"][axis]
        ):
            return _workspace_teach_unavailable(
                "captured minimum is outside hard box", True
            )
        if upper_value is not None and not (
            hard["lower"][axis] <= upper_value <= hard["upper"][axis]
        ):
            return _workspace_teach_unavailable(
                "captured maximum is outside hard box", True
            )
        if (
            lower_value is not None
            and upper_value is not None
            and lower_value > upper_value
            and state in ("review", "proposed")
        ):
            return _workspace_teach_unavailable("captured extrema are reversed", True)

    raw_tcp = raw.get("current_tcp_position_mm")
    if not isinstance(raw_tcp, (list, tuple)):
        return _workspace_teach_unavailable("current TCP position is malformed", True)
    if len(raw_tcp) == 0:
        current_tcp = ()
    else:
        current_tcp = _strict_twin_vector(raw_tcp, 3, -1_000_000.0, 1_000_000.0)
        if current_tcp is None:
            return _workspace_teach_unavailable(
                "current TCP position is malformed", True
            )
        if any(
            current_tcp[index] < hard["lower"][index]
            or current_tcp[index] > hard["upper"][index]
            for index in range(3)
        ):
            return _workspace_teach_unavailable("current TCP is outside hard box", True)
    if pose_ready and len(current_tcp) != 3:
        return _workspace_teach_unavailable("ready pose has no TCP evidence", True)

    proposal_digest = raw.get("proposal_sha256")
    if not isinstance(proposal_digest, str):
        return _workspace_teach_unavailable("proposal digest is malformed", True)
    if state in ("review", "proposed"):
        if completed != 6 or not _lower_hex(proposal_digest, 64):
            return _workspace_teach_unavailable("proposal evidence is incomplete", True)
    elif state == "cancelled" and proposal_digest:
        if completed != 6 or not _lower_hex(proposal_digest, 64):
            return _workspace_teach_unavailable("cancelled proposal is malformed", True)
    elif proposal_digest != "":
        return _workspace_teach_unavailable(
            "premature proposal digest was rejected", True
        )

    raw_blockers = raw.get("blockers")
    if (
        not isinstance(raw_blockers, (list, tuple))
        or len(raw_blockers) > len(_WORKSPACE_TEACH_BLOCKERS)
        or any(not isinstance(item, str) for item in raw_blockers)
        or len(set(raw_blockers)) != len(raw_blockers)
        or any(item not in _WORKSPACE_TEACH_BLOCKERS for item in raw_blockers)
    ):
        return _workspace_teach_unavailable("teach blockers are malformed", True)
    blockers = tuple(raw_blockers)
    if state == "idle" and blockers != ("session_not_started",):
        return _workspace_teach_unavailable("idle blocker is inconsistent", True)
    if state in ("cancelled", "proposed") and blockers != ("session_finished",):
        return _workspace_teach_unavailable("finished blocker is inconsistent", True)
    if state == "invalidated" and "session_invalidated" not in blockers:
        return _workspace_teach_unavailable("invalidated session lacks blocker", True)
    if state in ("ready_to_capture", "review") and blockers:
        return _workspace_teach_unavailable("ready teach state contains blockers", True)
    if state in ("awaiting_teach", "positioning") and not blockers:
        return _workspace_teach_unavailable("teach guidance lacks a blocker", True)
    if raw.get("safety_notice") != _WORKSPACE_TEACH_SAFETY_NOTICE:
        return _workspace_teach_unavailable("teach safety notice is invalid", True)

    state_labels = {
        "idle": ("WORKSPACE TEACH BEREIT", "warn", "START"),
        "awaiting_teach": ("CONTROLLER MODE 2 ERFORDERLICH", "warn", "MODE 2"),
        "positioning": ("TCP-POSITION STABILISIEREN", "warn", "GUIDED"),
        "ready_to_capture": ("POSE BEREIT ZUR ERFASSUNG", "ok", "CAPTURE"),
        "review": ("SECHS GRENZEN PRUEFEN", "warn", "REVIEW"),
        "proposed": ("PRUEFVORSCHLAG GESPEICHERT", "ok", "PROPOSED"),
        "cancelled": ("TEACH-SESSION VERWORFEN", "muted", "START"),
        "invalidated": ("TEACH-SESSION UNGUELTIG", "danger", "INVALID"),
    }
    headline, tone, status = state_labels[state]
    first_blocker = blockers[0].replace("_", " ").upper() if blockers else "READY"
    detail = (
        expected_guidance.get("instruction") if expected_guidance else first_blocker
    )
    return {
        "valid": True,
        "configured": True,
        "state": state,
        "tone": tone,
        "headline": headline,
        "detail": _safe_text(detail, 96),
        "status": status,
        "coordinate_frame": "xarm_base_mm",
        "required_controller_mode": 2,
        "session_id": session_id,
        "current_step": current_step,
        "completed_steps": completed,
        "total_steps": 6,
        "guidance": dict(expected_guidance),
        "pose_ready": pose_ready,
        "current_tcp_position_mm": current_tcp,
        "hard_envelope_mm": hard,
        "captured_bounds_mm": captured,
        "proposal_sha256": proposal_digest,
        "proposal_digest": proposal_digest[:12] if proposal_digest else "--",
        "blockers": blockers,
        "mode_two_blocked": "teach_mode_not_active" in blockers,
        "render_ready": True,
    }


def _workspace_boundary_unavailable(
    reason="workspace boundary validation unavailable",
    dangerous=False,
):
    return {
        "valid": False,
        "configured": False,
        "state": "unavailable",
        "tone": "danger" if dangerous else "muted",
        "headline": (
            "ARBEITSRAUM-VERTRAG UNGUELTIG" if dangerous else "ARBEITSRAUM-PRUEFUNG AUS"
        ),
        "detail": _safe_text(reason, 96),
        "status": "ERROR" if dangerous else "UNAVAILABLE",
        "session_id": "",
        "proposal_sha256": "",
        "robot_sha256": "",
        "bounds_mm": {"lower": (), "upper": ()},
        "cameras": {},
        "camera_evidence_sha256": "",
        "newton_version": "",
        "newton_model_sha256": "",
        "newton_result_sha256": "",
        "blockers": ("result_invalid",),
        "motion_authority": "none",
        "motion_authorized": False,
    }


def _workspace_boundary_view(runtime):
    """Strictly reduce the correlated dual-OAK/Newton boundary result."""

    raw_value = _mapping(runtime).get("workspace_boundary")
    if raw_value is None:
        return _workspace_boundary_unavailable()
    if not isinstance(raw_value, dict):
        return _workspace_boundary_unavailable("boundary is not an object", True)
    raw = raw_value
    if set(raw) != set(_WORKSPACE_BOUNDARY_KEYS):
        return _workspace_boundary_unavailable("boundary keys do not match v1", True)
    if raw.get("schema_version") != 1 or isinstance(raw.get("schema_version"), bool):
        return _workspace_boundary_unavailable("boundary schema is invalid", True)
    if not isinstance(raw.get("configured"), bool):
        return _workspace_boundary_unavailable("configured flag is invalid", True)
    state = raw.get("state")
    if state not in _WORKSPACE_BOUNDARY_STATES:
        return _workspace_boundary_unavailable("boundary state is invalid", True)
    if raw.get("configured") is not True:
        if state != "unavailable":
            return _workspace_boundary_unavailable(
                "disabled boundary state is inconsistent", True
            )
        return _workspace_boundary_unavailable()
    if (
        raw.get("motion_authority") != "none"
        or raw.get("motion_authorized") is not False
    ):
        return _workspace_boundary_unavailable("motion authority was rejected", True)

    session_id = raw.get("session_id")
    proposal = raw.get("proposal_sha256")
    robot = raw.get("robot_sha256")
    for value, length, name in (
        (session_id, 32, "session"),
        (proposal, 64, "proposal"),
        (robot, 64, "robot"),
    ):
        if state == "idle" and value == "":
            continue
        if not _lower_hex(value, length):
            return _workspace_boundary_unavailable(
                "{} binding is invalid".format(name), True
            )

    bounds = raw.get("bounds_mm")
    if not isinstance(bounds, dict) or set(bounds) != {"lower", "upper"}:
        return _workspace_boundary_unavailable("boundary box is invalid", True)
    if state == "idle":
        if bounds != {"lower": [], "upper": []}:
            return _workspace_boundary_unavailable("idle box is not empty", True)
        normalized_bounds = {"lower": (), "upper": ()}
    else:
        lower = _strict_twin_vector(bounds.get("lower"), 3, -1_000_000.0, 1_000_000.0)
        upper = _strict_twin_vector(bounds.get("upper"), 3, -1_000_000.0, 1_000_000.0)
        if (
            lower is None
            or upper is None
            or any(low >= high for low, high in zip(lower, upper))
        ):
            return _workspace_boundary_unavailable("boundary box is invalid", True)
        normalized_bounds = {"lower": lower, "upper": upper}

    raw_blockers = raw.get("blockers")
    if (
        not isinstance(raw_blockers, (list, tuple))
        or len(raw_blockers) > len(_WORKSPACE_BOUNDARY_BLOCKERS)
        or any(not isinstance(value, str) for value in raw_blockers)
        or len(set(raw_blockers)) != len(raw_blockers)
        or any(value not in _WORKSPACE_BOUNDARY_BLOCKERS for value in raw_blockers)
    ):
        return _workspace_boundary_unavailable("boundary blockers are invalid", True)
    blockers = tuple(raw_blockers)
    if state in ("idle", "validating", "valid") and blockers:
        return _workspace_boundary_unavailable(
            "boundary blockers are inconsistent", True
        )
    if state in ("blocked", "invalidated") and not blockers:
        return _workspace_boundary_unavailable("boundary blocker is missing", True)

    cameras = raw.get("cameras")
    if not isinstance(cameras, dict) or set(cameras) != {"tool", "workspace"}:
        return _workspace_boundary_unavailable("camera bindings are invalid", True)
    normalized_cameras = {}
    for role in ("tool", "workspace"):
        camera = cameras.get(role)
        if not isinstance(camera, dict) or set(camera) != {
            "source_id",
            "frame_sequence",
            "calibration_sha256",
        }:
            return _workspace_boundary_unavailable("camera binding is invalid", True)
        source = camera.get("source_id")
        sequence = camera.get("frame_sequence")
        digest = camera.get("calibration_sha256")
        if state == "valid":
            if (
                not isinstance(source, str)
                or not source
                or isinstance(sequence, bool)
                or not isinstance(sequence, int)
                or sequence <= 0
                or not _lower_hex(digest, 64)
            ):
                return _workspace_boundary_unavailable(
                    "camera binding is incomplete", True
                )
        normalized_cameras[role] = dict(camera)
    if state == "valid" and (
        normalized_cameras["tool"]["source_id"]
        == normalized_cameras["workspace"]["source_id"]
    ):
        return _workspace_boundary_unavailable("cameras are not distinct", True)

    digest_fields = (
        "camera_evidence_sha256",
        "newton_model_sha256",
        "newton_result_sha256",
    )
    for name in digest_fields:
        value = raw.get(name)
        if not isinstance(value, str) or (
            state == "valid" and not _lower_hex(value, 64)
        ):
            return _workspace_boundary_unavailable("{} is invalid".format(name), True)
    newton_version = raw.get("newton_version")
    version_parts = newton_version.split(".") if isinstance(newton_version, str) else []
    if not isinstance(newton_version, str) or (
        state == "valid"
        and (
            len(version_parts) != 3
            or any(not part or not part.isdigit() for part in version_parts)
        )
    ):
        return _workspace_boundary_unavailable("Newton version is invalid", True)

    labels = {
        "idle": ("ARBEITSRAUM EINMESSEN", "warn", "START"),
        "validating": ("2x OAK + NEWTON PRUEFEN", "warn", "CHECKING"),
        "valid": ("APP-ARBEITSRAUM GUELTIG", "ok", "VALID"),
        "blocked": ("ARBEITSRAUM BLOCKIERT", "danger", "BLOCKED"),
        "invalidated": ("PRUEFUNG DURCH STOP VERWORFEN", "danger", "STOPPED"),
        "unavailable": ("ARBEITSRAUM-PRUEFUNG AUS", "muted", "UNAVAILABLE"),
    }
    headline, tone, status = labels[state]
    detail = (
        "Beide OAK-Tiefenbilder und Newton 1.4 sind exakt gebunden"
        if state == "valid"
        else (
            blockers[0].replace("_", " ").upper()
            if blockers
            else "Ein Teach-Abschluss startet die Pruefung automatisch"
        )
    )
    return {
        "valid": True,
        "configured": True,
        "state": state,
        "tone": tone,
        "headline": headline,
        "detail": _safe_text(detail, 96),
        "status": status,
        "session_id": session_id,
        "proposal_sha256": proposal,
        "robot_sha256": robot,
        "bounds_mm": normalized_bounds,
        "cameras": normalized_cameras,
        "camera_evidence_sha256": raw.get("camera_evidence_sha256"),
        "newton_version": newton_version,
        "newton_model_sha256": raw.get("newton_model_sha256"),
        "newton_result_sha256": raw.get("newton_result_sha256"),
        "blockers": blockers,
        "motion_authority": "none",
        "motion_authorized": False,
    }


def _project_workspace_teach_geometry(teach, width, height):
    """Render-only isometric projection for hard box, captured planes and TCP."""

    teach = _mapping(teach)
    if (
        teach.get("valid") is not True
        or isinstance(width, bool)
        or isinstance(height, bool)
        or not isinstance(width, int)
        or not isinstance(height, int)
        or not 64 <= width <= 4096
        or not 64 <= height <= 4096
    ):
        return {"valid": False, "hard_edges": (), "captured_faces": (), "tcp": None}
    hard = _mapping(teach.get("hard_envelope_mm"))
    lower = hard.get("lower")
    upper = hard.get("upper")
    if not (
        isinstance(lower, (list, tuple))
        and isinstance(upper, (list, tuple))
        and len(lower) == 3
        and len(upper) == 3
    ):
        return {"valid": False, "hard_edges": (), "captured_faces": (), "tcp": None}

    def project(point):
        x, y, z = point
        return (
            (x - y) * 0.70710678,
            ((x + y) * 0.40824829) - (z * 0.81649658),
        )

    lx, ly, lz = lower
    ux, uy, uz = upper
    corners = (
        (lx, ly, lz),
        (ux, ly, lz),
        (ux, uy, lz),
        (lx, uy, lz),
        (lx, ly, uz),
        (ux, ly, uz),
        (ux, uy, uz),
        (lx, uy, uz),
    )
    projected = tuple(project(point) for point in corners)
    minimum_u = min(point[0] for point in projected)
    maximum_u = max(point[0] for point in projected)
    minimum_v = min(point[1] for point in projected)
    maximum_v = max(point[1] for point in projected)
    span_u = maximum_u - minimum_u
    span_v = maximum_v - minimum_v
    if span_u <= 0.0 or span_v <= 0.0:
        return {"valid": False, "hard_edges": (), "captured_faces": (), "tcp": None}
    padding = max(10, min(28, min(width, height) // 12))
    available_width = width - (padding * 2)
    available_height = height - (padding * 2)
    scale = min(available_width / span_u, available_height / span_v)
    used_width = span_u * scale
    used_height = span_v * scale
    offset_x = padding + ((available_width - used_width) / 2.0)
    offset_y = padding + ((available_height - used_height) / 2.0)

    def pixel(point):
        u, v = project(point)
        return (
            min(max(int(round(offset_x + ((u - minimum_u) * scale))), 0), width - 1),
            min(max(int(round(offset_y + ((v - minimum_v) * scale))), 0), height - 1),
        )

    pixel_corners = tuple(pixel(point) for point in corners)
    edge_indexes = (
        (0, 1),
        (1, 2),
        (2, 3),
        (3, 0),
        (4, 5),
        (5, 6),
        (6, 7),
        (7, 4),
        (0, 4),
        (1, 5),
        (2, 6),
        (3, 7),
    )
    hard_edges = tuple(
        (pixel_corners[first], pixel_corners[second]) for first, second in edge_indexes
    )
    captured = _mapping(teach.get("captured_bounds_mm"))
    faces = []
    values = (
        ("x_min", 0, captured.get("lower", (None,) * 3)[0]),
        ("x_max", 0, captured.get("upper", (None,) * 3)[0]),
        ("y_min", 1, captured.get("lower", (None,) * 3)[1]),
        ("y_max", 1, captured.get("upper", (None,) * 3)[1]),
        ("z_min", 2, captured.get("lower", (None,) * 3)[2]),
        ("z_max", 2, captured.get("upper", (None,) * 3)[2]),
    )
    for step, axis, value in values:
        if value is None:
            continue
        if axis == 0:
            plane = ((value, ly, lz), (value, uy, lz), (value, uy, uz), (value, ly, uz))
        elif axis == 1:
            plane = ((lx, value, lz), (ux, value, lz), (ux, value, uz), (lx, value, uz))
        else:
            plane = ((lx, ly, value), (ux, ly, value), (ux, uy, value), (lx, uy, value))
        pixels = tuple(pixel(point) for point in plane)
        faces.append(
            (
                step,
                tuple((pixels[index], pixels[(index + 1) % 4]) for index in range(4)),
            )
        )
    tcp = teach.get("current_tcp_position_mm")
    return {
        "valid": True,
        "hard_edges": hard_edges,
        "captured_faces": tuple(faces),
        "tcp": pixel(tcp) if isinstance(tcp, (list, tuple)) and len(tcp) == 3 else None,
    }


def _diagnostics_view(view):
    """Return the fixed, secret-free diagnostics surface used by Button 6."""

    raw = _mapping(_mapping(view).get("diagnostics"))
    if raw.get("schema_version") != 1:
        raw = {}
    operator = _mapping(raw.get("operator"))
    management = _mapping(operator.get("management"))
    xarm = _mapping(operator.get("xarm"))
    camera_map = _mapping(operator.get("cameras"))
    capabilities = _mapping(raw.get("capabilities"))
    if capabilities.get("schema_version") != 1:
        capabilities = {}
    datahub = _mapping(raw.get("datahub"))
    outbox = _mapping(datahub.get("outbox"))
    outbox_schema = outbox.get("schema_version")
    outbox_valid = not isinstance(outbox_schema, bool) and outbox_schema == 1
    last_acknowledgement_age = (
        _bounded_number(
            outbox.get("last_acknowledgement_age_seconds"),
            minimum=0.0,
            maximum=315_576_000.0,
        )
        if outbox_valid
        else None
    )
    registry = _mapping(raw.get("registry"))
    system = _mapping(raw.get("system"))
    if system.get("schema_version") != 1:
        system = {}

    cameras = {}
    for role in ("tool", "workspace"):
        camera = _mapping(camera_map.get(role))
        backend = _safe_text(camera.get("backend") or "unknown", 16)
        if backend not in ("depthai", "opencv", "unknown"):
            backend = "unknown"
        state = _safe_text(camera.get("state") or "unavailable", 16)
        if state not in ("stopped", "starting", "running", "degraded"):
            state = "unavailable"
        cameras[role] = {
            "configured": camera.get("configured") is True,
            "backend": backend,
            "source_id": _safe_text(camera.get("source_id"), 80),
            "mxid": _safe_text(camera.get("mxid"), 80),
            "state": state,
            "fresh": camera.get("fresh") is True,
            "stream": _safe_text(camera.get("stream_url"), 120),
        }

    workers = []
    raw_workers = _mapping(raw.get("workers"))
    for name in sorted(raw_workers)[:24]:
        status = _mapping(raw_workers.get(name))
        workers.append(
            {
                "name": _safe_text(name, 48),
                "configured": status.get("configured") is True,
                "running": status.get("running") is True,
            }
        )

    cpu = _mapping(system.get("cpu"))
    memory = _mapping(system.get("memory"))
    filesystem = _mapping(system.get("state_filesystem"))
    temperature = _mapping(system.get("temperature"))
    capability_summary = {}
    for name in (
        "registry",
        "datahub",
        "ota",
        "capture",
        "capture_export",
        "offload",
        "calibration",
        "dynamic_valve_search",
        "motion",
        "petri",
        "software_stop",
    ):
        item = _mapping(capabilities.get(name))
        capability_summary[name] = {
            "configured": item.get("configured") is True,
            "ready": bool(
                item.get("ready") is True
                or item.get("action_allowed") is True
                or item.get("available") is True
            ),
            "state": _safe_text(item.get("state") or item.get("status"), 24),
        }

    deployment_mode = _safe_text(
        operator.get("deployment_mode") or raw.get("deployment_mode") or "unknown",
        16,
    )
    if deployment_mode not in (
        "development",
        "gateway",
        "operator",
        "workcell",
        "production",
    ):
        deployment_mode = "unknown"
    exposure = _safe_text(management.get("exposure") or "disabled", 24)
    if exposure not in ("disabled", "loopback", "authenticated_network"):
        exposure = "disabled"
    registry_status = _safe_text(registry.get("status") or "off", 16)
    if registry_status not in ("off", "pending", "verified", "incomplete", "error"):
        registry_status = "error"
    return {
        "deployment_mode": deployment_mode,
        "hostname": _safe_text(operator.get("hostname") or system.get("hostname"), 64),
        "management": {
            "configured": management.get("configured") is True,
            "exposure": exposure,
            "bind_address": _safe_text(management.get("bind_address"), 64),
            "port": _bounded_count(management.get("port"), 65535),
            "bearer_auth_configured": (
                management.get("bearer_auth_configured") is True
            ),
            "controls": (
                "loopback_only"
                if management.get("controls") == "loopback_only"
                else "unavailable"
            ),
            "health_url": _safe_text(management.get("health_url"), 120),
        },
        "network": {
            "xarm_private_address": _safe_text(xarm.get("private_address"), 64),
            "cameras": cameras,
        },
        "datahub": {
            "configured": datahub.get("configured") is True,
            "available": datahub.get("available") is True,
            "pending": _bounded_count(datahub.get("pending")),
            "dead_letters": _bounded_count(datahub.get("dead_letters")),
            "dataset_binding_verified": (
                datahub.get("dataset_binding_verified") is True
            ),
            "outbox_valid": outbox_valid,
            "last_acknowledgement_age_seconds": last_acknowledgement_age,
        },
        "registry": {
            "configured": registry.get("configured") is True,
            "ready": registry.get("ready") is True,
            "status": registry_status,
        },
        "workers": workers,
        "system": {
            "uptime_seconds": _bounded_number(system.get("uptime_seconds")),
            "cpu_cores": _bounded_count(cpu.get("logical_cores"), 4096),
            "load_1m": _bounded_number(cpu.get("load_1m"), maximum=1_000_000),
            "memory_total": _bounded_count(memory.get("total_bytes"), 2**63 - 1),
            "memory_available": _bounded_count(
                memory.get("available_bytes"), 2**63 - 1
            ),
            "disk_total": _bounded_count(filesystem.get("total_bytes"), 2**63 - 1),
            "disk_free": _bounded_count(filesystem.get("free_bytes"), 2**63 - 1),
            "temperature_c": _bounded_number(
                temperature.get("celsius"), minimum=-50.0, maximum=200.0
            ),
        },
        "capabilities": capability_summary,
    }


def _hand_training_view(runtime):
    """Reduce the two-camera recording contract for the dedicated page."""

    raw = _mapping(_mapping(runtime).get("hand_training"))
    unavailable = {
        "configured": False,
        "state": "unavailable",
        "active": False,
        "start_allowed": False,
        "end_allowed": False,
        "tool_allowed": False,
        "tool_on": False,
        "sample_count": 0,
        "elapsed_seconds": 0.0,
        "sample_rate_hz": 0.0,
        "uploaded": False,
        "recording_id": "",
        "workbench_rows": 0,
        "shortcut_jobs": 0,
        "error_code": "",
    }
    if raw.get("schema_version") != 1 or not isinstance(
        raw.get("configured"), bool
    ):
        return unavailable
    state = _safe_text(raw.get("state") or "unavailable", 24)
    if state not in (
        "idle",
        "starting",
        "recording",
        "stopping",
        "uploading",
        "completed",
        "failed",
        "cancelled",
        "unavailable",
    ):
        return unavailable
    result = dict(unavailable)
    result.update(
        {
            "configured": raw.get("configured") is True,
            "state": state,
            "active": raw.get("active") is True,
            "start_allowed": raw.get("start_allowed") is True,
            "end_allowed": raw.get("end_allowed") is True,
            "tool_allowed": raw.get("tool_allowed") is True,
            "tool_on": raw.get("tool_on") is True,
            "sample_count": _bounded_count(raw.get("sample_count"), 1_000_000)
            or 0,
            "elapsed_seconds": _bounded_number(
                raw.get("elapsed_seconds"), minimum=0.0, maximum=3600.0
            )
            or 0.0,
            "sample_rate_hz": _bounded_number(
                raw.get("sample_rate_hz"), minimum=0.0, maximum=30.0
            )
            or 0.0,
            "uploaded": raw.get("uploaded") is True,
            "recording_id": _safe_text(raw.get("recording_id") or "", 64),
            "workbench_rows": _bounded_count(raw.get("workbench_rows"), 10000)
            or 0,
            "shortcut_jobs": _bounded_count(raw.get("shortcut_jobs"), 10000)
            or 0,
            "error_code": _safe_text(raw.get("error_code") or "", 64),
        }
    )
    return result


def present_health(response):
    """Reduce a backend health document to bounded, secret-free UI strings."""

    response = _mapping(response)
    raw_payload = response.get("payload")
    payload = _mapping(raw_payload)
    try:
        http_status = int(response.get("http_status") or 0)
    except (TypeError, ValueError):
        http_status = 0
    reported_ready = http_status == 200 and payload.get("ready") is True
    raw_runtime = payload.get("runtime")
    runtime = _mapping(raw_runtime)
    # Both 200 (ready) and 503 (degraded) are intentional health responses.
    # Transport failures and shape-invalid documents are never authoritative
    # enough to release an already-admitted motion STOP latch.
    health_authoritative = (
        http_status in (200, 503)
        and isinstance(raw_payload, dict)
        and isinstance(raw_runtime, dict)
        and isinstance(payload.get("ready"), bool)
    )
    ready = bool(reported_ready and health_authoritative)
    payload_cameras = payload.get("cameras")
    if not isinstance(payload_cameras, dict):
        payload_cameras = {}
    runtime_cameras = _mapping(runtime.get("cameras"))
    cameras = {}
    for role in ("tool", "workspace"):
        merged = dict(_mapping(runtime_cameras.get(role)))
        merged.update(_mapping(payload_cameras.get(role)))
        cameras[role] = merged
    operator_diagnostics = _mapping(runtime.get("operator_diagnostics"))
    diagnostic_cameras = (
        _mapping(operator_diagnostics.get("cameras"))
        if operator_diagnostics.get("schema_version") == 1
        else {}
    )
    tool = _camera_view(cameras, "tool", diagnostic_cameras.get("tool"))
    workspace = _camera_view(
        cameras,
        "workspace",
        diagnostic_cameras.get("workspace"),
    )
    motion = dict(_motion_view(runtime))
    raw_motion = _mapping(runtime.get("motion"))
    # Preserve only the two authorization booleans needed by the display-local
    # no-sleep gate.  They remain status evidence and never grant an action.
    motion["armed"] = raw_motion.get("armed") is True
    motion["live"] = raw_motion.get("live") is True
    ota = _ota_view(runtime)
    capture = _capture_view(runtime)
    xarm = _xarm_view(runtime)
    digital_twin = _digital_twin_view(runtime)
    workspace_teach = _workspace_teach_view(runtime)
    workspace_boundary = _workspace_boundary_view(runtime)
    tenant_auth = _tenant_auth_view(runtime)
    hand_training = _hand_training_view(runtime)
    runtime_role = _runtime_role_view(runtime)
    operations = _operations_view({"operations": runtime.get("operations")})
    raw_diagnostics = {
        "schema_version": 1,
        "deployment_mode": runtime.get("deployment_mode"),
        "operator": runtime.get("operator_diagnostics"),
        "capabilities": runtime.get("capabilities"),
        "workers": runtime.get("worker_inventory"),
        "system": runtime.get("system"),
        "datahub": runtime.get("datahub"),
        "registry": runtime.get("registry"),
    }
    capabilities = _mapping(runtime.get("capabilities"))
    search_capability = _mapping(capabilities.get("dynamic_valve_search"))
    motion_search = {
        "schema_version": 1 if capabilities.get("schema_version") == 1 else 0,
        "deployment_mode": runtime.get("deployment_mode"),
        "configured": search_capability.get("configured") is True,
        "action_allowed": search_capability.get("action_allowed") is True,
        "requires_two_step_confirmation": (
            search_capability.get("requires_two_step_confirmation") is True
        ),
        "state": search_capability.get("state"),
        "last_target_review": _mapping(runtime.get("motion")).get("last_target_review"),
    }
    problems = runtime.get("problems") or payload.get("problems") or []
    if not isinstance(problems, (list, tuple)):
        problems = []
    problem_text = ", ".join(_safe_text(item, 32) for item in problems[:2])
    if not problem_text:
        problem_text = "none" if ready else "health checks incomplete"
    camera_count = 0
    if tool["healthy"]:
        camera_count += 1
    if workspace["healthy"]:
        camera_count += 1
    return {
        "health_authoritative": health_authoritative,
        "deployment_mode": runtime_role["mode"],
        "runtime_role": runtime_role,
        "ready": ready,
        "tone": "ok" if ready else "warn" if health_authoritative else "danger",
        "state": (
            "SYSTEM READY"
            if ready
            else (
                "ATTENTION REQUIRED"
                if health_authoritative
                else "HEALTH CONTRACT INVALID"
            )
        ),
        "detail": (
            "All required runtime checks are passing"
            if ready
            else (
                "One or more runtime checks need attention"
                if health_authoritative
                else "Local health response is unavailable or malformed"
            )
        ),
        "camera_count": camera_count,
        "tool": tool["legacy"],
        "workspace": workspace["legacy"],
        "cameras": {"tool": tool, "workspace": workspace},
        "motion": motion,
        "ota": ota,
        "capture": capture,
        "xarm": xarm,
        "digital_twin": digital_twin,
        "workspace_teach": workspace_teach,
        "workspace_boundary": workspace_boundary,
        "tenant_auth": tenant_auth,
        "hand_training": hand_training,
        "motion_search": motion_search,
        "operations": operations,
        "diagnostics": raw_diagnostics,
        "footer": (
            "NO ACTIVE FAULTS"
            if ready
            else (
                _safe_text(problem_text, 72)
                if health_authoritative
                else "LOCAL HEALTH RESPONSE INVALID"
            )
        ),
        "problems": "Checks: %s" % problem_text,
    }


def _xarm_view(runtime):
    """Reduce the bounded runtime xArm snapshot for read-only display."""

    xarm = _mapping(_mapping(runtime).get("xarm"))
    valid = (
        xarm.get("schema_version") == 1
        and isinstance(xarm.get("configured"), bool)
        and isinstance(xarm.get("connected"), bool)
        and isinstance(xarm.get("healthy"), bool)
        and isinstance(xarm.get("fresh"), bool)
        and isinstance(xarm.get("moving"), bool)
    )
    if not valid:
        return {
            "valid": False,
            "configured": False,
            "connected": False,
            "healthy": False,
            "fresh": False,
            "moving": False,
            "system_check_ok": False,
            "motion_ready": False,
            "control_setup_required": False,
            "summary": "UNAVAILABLE",
            "detail": "xArm telemetry contract unavailable",
            "guidance": "No robot run: verify the bounded xArm health service.",
            "error_code": None,
            "warning_code": None,
            "state": None,
            "mode": None,
            "axis_count": None,
            "device_type": None,
            "reduced_mode_enabled": False,
            "reduced_configuration_valid": False,
            "reduced_safety_boundary_enabled": False,
            "collision_rebound_disabled": False,
            "conservative_joint_envelope": False,
            "control_envelope_ready": False,
            "metrics": {},
            "safety_configurator": {},
            "tone": "muted",
        }
    configured = xarm.get("configured") is True
    connected = xarm.get("connected") is True
    healthy = xarm.get("healthy") is True
    fresh = xarm.get("fresh") is True
    moving = xarm.get("moving") is True
    error_code = xarm.get("error_code")
    warning_code = xarm.get("warning_code")
    safe_codes = (
        isinstance(error_code, int)
        and not isinstance(error_code, bool)
        and isinstance(warning_code, int)
        and not isinstance(warning_code, bool)
    )
    error_clear = safe_codes and error_code == 0
    warning_clear = safe_codes and warning_code == 0
    system_check_ok = bool(
        configured and connected and healthy and fresh and error_clear and warning_clear
    )
    reduced_mode_enabled = xarm.get("reduced_mode_enabled") is True
    reduced_configuration_valid = xarm.get("reduced_configuration_valid") is True
    conservative_joint_envelope = xarm.get("conservative_joint_envelope") is True
    control_envelope_ready = xarm.get("control_envelope_ready") is True
    motion_ready = (
        system_check_ok
        and not moving
        and reduced_mode_enabled
        and reduced_configuration_valid
        and conservative_joint_envelope
        and control_envelope_ready
    )
    control_setup_required = bool(system_check_ok and not moving and not motion_ready)
    detail = "State %s / Mode %s / Error %s / Warning %s" % (
        (
            _safe_text(str(xarm.get("state")), 8)
            if xarm.get("state") is not None
            else "--"
        ),
        _safe_text(str(xarm.get("mode")), 8) if xarm.get("mode") is not None else "--",
        _safe_text(str(error_code), 8) if safe_codes else "--",
        _safe_text(str(warning_code), 8) if safe_codes else "--",
    )
    if not configured:
        summary = "CONTROL MODE AUS"
        guidance = "Lokalen ROBOT CONTROL MODE fuer Button 03 aktivieren."
        tone = "muted"
    elif safe_codes and error_code == 2:
        summary = "EMERGENCY-IO OPEN"
        guidance = (
            "Error 2: external Emergency-IO is open. Check E-stop and safety wiring."
        )
        tone = "danger"
    elif safe_codes and error_code != 0:
        summary = "CONTROLLER ERROR %d" % error_code
        guidance = "Inspect the xArm controller and safety chain; motion stays blocked."
        tone = "danger"
    elif not connected:
        summary = "xARM DISCONNECTED"
        guidance = "Check controller power and the read-only telemetry connection."
        tone = "warn"
    elif not fresh:
        summary = "TELEMETRY STALE"
        guidance = "Wait for a fresh controller sample before any robot run."
        tone = "warn"
    elif moving:
        summary = "MOVING"
        guidance = "Motion is active; keep clear and use the visible SOFTWARE STOP."
        tone = "danger"
    elif not healthy:
        summary = "xARM UNHEALTHY"
        guidance = "Inspect controller health and safety inputs; motion stays blocked."
        tone = "danger"
    elif safe_codes and warning_code != 0:
        summary = "CONTROLLER WARNING %d" % warning_code
        guidance = "Review the controller warning before a robot run."
        tone = "warn"
    elif motion_ready:
        summary = "xARM CONNECTED / SYSTEM CHECK OK"
        guidance = "Controller health, telemetry and motion safeguards are ready."
        tone = "ok"
    elif system_check_ok:
        summary = "xARM CONNECTED / SYSTEM CHECK OK"
        guidance = "Controller health, telemetry and error checks are OK."
        tone = "ok"
    else:
        summary = "CHECK"
        guidance = "Robot readiness could not be verified; motion stays blocked."
        tone = "warn"
    return {
        "valid": True,
        "configured": configured,
        "connected": connected,
        "healthy": healthy,
        "fresh": fresh,
        "moving": moving,
        "system_check_ok": system_check_ok,
        "motion_ready": motion_ready,
        "control_setup_required": control_setup_required,
        "summary": summary,
        "detail": detail,
        "guidance": _safe_text(guidance, 96),
        "error_code": error_code if safe_codes else None,
        "warning_code": warning_code if safe_codes else None,
        "state": xarm.get("state"),
        "mode": xarm.get("mode"),
        "axis_count": xarm.get("axis_count"),
        "device_type": xarm.get("device_type"),
        "reduced_mode_enabled": reduced_mode_enabled,
        "reduced_configuration_valid": reduced_configuration_valid,
        "reduced_safety_boundary_enabled": (
            xarm.get("reduced_safety_boundary_enabled") is True
        ),
        "collision_rebound_disabled": (xarm.get("collision_rebound_disabled") is True),
        "conservative_joint_envelope": conservative_joint_envelope,
        "control_envelope_ready": control_envelope_ready,
        "metrics": (
            dict(xarm.get("metrics")) if isinstance(xarm.get("metrics"), dict) else {}
        ),
        "safety_configurator": (
            dict(xarm.get("safety_configurator"))
            if isinstance(xarm.get("safety_configurator"), dict)
            else {}
        ),
        "tone": tone,
    }


def _robot_optional_number(value, minimum, maximum):
    """Validate one optional finite telemetry number without coercion."""

    if value is None:
        return True, None
    if isinstance(value, bool) or not isinstance(value, (int, float)):
        return False, None
    number = float(value)
    if number != number or number < minimum or number > maximum:
        return False, None
    return True, number


def _robot_optional_integer(value, maximum):
    if value is None:
        return True, None
    if isinstance(value, bool) or not isinstance(value, int):
        return False, None
    if value < 0 or value > maximum:
        return False, None
    return True, value


def _robot_optional_vector(value, length, minimum, maximum):
    if value is None:
        return True, None
    if not isinstance(value, (list, tuple)) or len(value) != length:
        return False, None
    result = []
    for item in value:
        valid, number = _robot_optional_number(item, minimum, maximum)
        if not valid or number is None:
            return False, None
        result.append(number)
    return True, result


def _robot_optional_binary_vector(value, length=6):
    if value is None:
        return True, None
    if not isinstance(value, (list, tuple)) or len(value) != length:
        return False, None
    result = []
    for item in value:
        if isinstance(item, bool):
            result.append(item)
        elif isinstance(item, int) and item in (0, 1):
            result.append(item == 1)
        else:
            return False, None
    return True, result


def _robot_metric(label, value, tone, fresh=True):
    if not fresh and tone == "ok":
        tone = "warn"
    if tone not in ("ok", "warn", "danger", "muted"):
        tone = "muted"
    safe_value = _safe_text(value or "UNAVAILABLE", 120) or "UNAVAILABLE"
    # A fresh sample can legitimately omit optional controller channels.
    # Missing data is neutral; it must never inherit the live/green tone.
    if safe_value == "UNAVAILABLE":
        tone = "muted"
    return {
        "label": _safe_text(label or "METRIC", 48) or "METRIC",
        "value": safe_value,
        "tone": tone,
    }


def _robot_number_text(value, suffix="", digits=1):
    if value is None:
        return "UNAVAILABLE"
    pattern = "%%.%df" % digits
    return (pattern % value) + suffix


def _robot_vector_text(values, suffix="", digits=1):
    if values is None:
        return "UNAVAILABLE"
    pattern = "%%.%df" % digits
    return " / ".join((pattern % value) + suffix for value in values)


def _robot_version_text(value):
    if not isinstance(value, str) or not value or len(value) > 64:
        return "UNAVAILABLE"
    allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._+-"
    if any(character not in allowed for character in value):
        return "UNAVAILABLE"
    return value


def _robot_metrics_unavailable_pages():
    labels = (
        (
            "STATUS",
            (
                "CONNECTION",
                "SAMPLE AGE",
                "STATE",
                "MODE",
                "MOTION",
                "ERROR",
                "WARNING",
                "QUEUE",
                "REDUCED MODE",
                "TCP SAFETY BOUNDARY",
                "COLLISION REBOUND",
                "CONTROL ENVELOPE",
            ),
        ),
        (
            "TCP",
            (
                "TCP POSITION",
                "TCP ORIENTATION DEG",
                "TCP ORIENTATION RAD",
                "TCP LOAD",
                "CENTER OF GRAVITY",
                "TCP BOUNDARY",
                "TCP SPEED",
                "TCP MAX",
            ),
        ),
        ("JOINTS", ("J1", "J2", "J3", "J4", "J5", "J6")),
        (
            "CONTROLLER",
            (
                "FIRMWARE",
                "AXIS",
                "DEVICE",
                "TEMPERATURE C",
                "VOLTAGE V",
                "CURRENT A",
                "SDK TORQUE/CURRENT",
                "MOTOR ENABLE",
                "MOTOR BRAKE",
                "COLLISION SENSITIVITY",
                "TEACH SENSITIVITY",
                "JOINT SPEED",
                "JOINT LIMIT",
            ),
        ),
    )
    return [
        {
            "title": title,
            "metrics": [
                _robot_metric(label, "UNAVAILABLE", "muted", fresh=False)
                for label in page_labels
            ],
        }
        for title, page_labels in labels
    ]


def _robot_metrics_view(view):
    """Reduce every versioned xArm metric into four bounded touch pages."""

    xarm = _mapping(_mapping(view).get("xarm"))
    raw = xarm.get("metrics")
    if (
        not isinstance(raw, dict)
        or raw.get("schema_version") != 1
        or isinstance(raw.get("schema_version"), bool)
    ):
        pages = _robot_metrics_unavailable_pages()
        return {"valid": False, "fresh": False, "page_count": 4, "pages": pages}

    malformed = False
    if not isinstance(raw.get("fresh"), bool):
        malformed = True
        fresh = False
    else:
        fresh = raw.get("fresh") is True and xarm.get("fresh") is True
    age_valid, sample_age = _robot_optional_number(
        raw.get("sample_age_seconds"), 0.0, 86400.0
    )
    queue_valid, queue_depth = _robot_optional_integer(
        raw.get("command_queue_depth"), 1_000_000
    )
    malformed = malformed or not age_valid or sample_age is None or not queue_valid

    vector_specs = {
        "joint_angles_deg": (6, -36000.0, 36000.0),
        "joint_angles_rad": (6, -1000.0, 1000.0),
        "joint_velocity_rad_s": (6, -1000.0, 1000.0),
        "joint_effort": (6, -1000000.0, 1000000.0),
        "tcp_position_mm": (3, -1000000.0, 1000000.0),
        "tcp_orientation_deg": (3, -36000.0, 36000.0),
        "tcp_orientation_rad": (3, -1000.0, 1000.0),
    }
    vectors = {}
    for name, spec in vector_specs.items():
        valid, parsed = _robot_optional_vector(raw.get(name), *spec)
        malformed = malformed or not valid
        vectors[name] = parsed

    controller = raw.get("controller")
    safety = raw.get("safety")
    if not isinstance(controller, dict) or not isinstance(safety, dict):
        pages = _robot_metrics_unavailable_pages()
        return {"valid": False, "fresh": False, "page_count": 4, "pages": pages}

    controller_vectors = {}
    for name, spec in {
        "temperatures_c": (6, -100.0, 250.0),
        "joint_voltages_v": (6, 0.0, 1000.0),
        "joint_currents_a": (6, -1000.0, 1000.0),
        "joint_torque_or_current_sdk": (6, -10000.0, 10000.0),
        "tcp_center_of_gravity_mm": (3, -1000000.0, 1000000.0),
    }.items():
        valid, parsed = _robot_optional_vector(controller.get(name), *spec)
        malformed = malformed or not valid
        controller_vectors[name] = parsed
    enable_valid, motor_enable = _robot_optional_binary_vector(
        controller.get("motor_enable_states")
    )
    brake_valid, motor_brake = _robot_optional_binary_vector(
        controller.get("motor_brake_states")
    )
    malformed = malformed or not enable_valid or not brake_valid
    controller_numbers = {}
    for name, bounds in {
        "tcp_load_kg": (0.0, 10000.0),
    }.items():
        valid, parsed = _robot_optional_number(controller.get(name), *bounds)
        malformed = malformed or not valid
        controller_numbers[name] = parsed
    controller_integers = {}
    for name, maximum in {
        "axis_count": 32,
        "device_type": 65535,
        "collision_sensitivity": 5,
        "teach_sensitivity": 5,
    }.items():
        valid, parsed = _robot_optional_integer(controller.get(name), maximum)
        malformed = malformed or not valid
        controller_integers[name] = parsed

    safety_vectors = {}
    for name, spec in {
        "tcp_boundary_min_mm": (3, -1000000.0, 1000000.0),
        "tcp_boundary_max_mm": (3, -1000000.0, 1000000.0),
        "joint_lower_rad": (6, -1000.0, 1000.0),
        "joint_upper_rad": (6, -1000.0, 1000.0),
    }.items():
        valid, parsed = _robot_optional_vector(safety.get(name), *spec)
        malformed = malformed or not valid
        safety_vectors[name] = parsed
    safety_numbers = {}
    for name, bounds in {
        "max_tcp_speed_mm_s": (0.0, 1000000.0),
        "max_joint_speed_rad_s": (0.0, 1000.0),
    }.items():
        valid, parsed = _robot_optional_number(safety.get(name), *bounds)
        malformed = malformed or not valid
        safety_numbers[name] = parsed
    for name in ("safety_boundary_enabled", "collision_rebound_enabled"):
        if safety.get(name) is not None and not isinstance(safety.get(name), bool):
            malformed = True

    if malformed:
        pages = _robot_metrics_unavailable_pages()
        return {"valid": False, "fresh": False, "page_count": 4, "pages": pages}

    base_tone = "ok" if fresh else "warn"
    connected = xarm.get("connected") is True
    moving = xarm.get("moving") is True
    error = xarm.get("error_code")
    warning = xarm.get("warning_code")
    status_metrics = [
        _robot_metric(
            "CONNECTION",
            "CONNECTED" if connected else "DISCONNECTED",
            base_tone if connected else "danger",
            fresh,
        ),
        _robot_metric(
            "SAMPLE AGE",
            _robot_number_text(sample_age, " S", 2),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "STATE",
            str(xarm.get("state") if xarm.get("state") is not None else "--"),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "MODE",
            str(xarm.get("mode") if xarm.get("mode") is not None else "--"),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "MOTION",
            "MOVING" if moving else "STATIONARY",
            "danger" if moving else base_tone,
            fresh,
        ),
        _robot_metric(
            "ERROR",
            str(error if error is not None else "--"),
            "danger" if error not in (0, None) else base_tone,
            fresh,
        ),
        _robot_metric(
            "WARNING",
            str(warning if warning is not None else "--"),
            "warn" if warning not in (0, None) else base_tone,
            fresh,
        ),
        _robot_metric(
            "QUEUE",
            str(queue_depth if queue_depth is not None else "UNAVAILABLE"),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "REDUCED MODE",
            "ON" if xarm.get("reduced_mode_enabled") is True else "OFF",
            base_tone if xarm.get("reduced_mode_enabled") is True else "warn",
            fresh,
        ),
        _robot_metric(
            "TCP SAFETY BOUNDARY",
            "ON" if xarm.get("reduced_safety_boundary_enabled") is True else "OFF",
            (
                base_tone
                if xarm.get("reduced_safety_boundary_enabled") is True
                else "warn"
            ),
            fresh,
        ),
        _robot_metric(
            "COLLISION REBOUND",
            "DISABLED" if xarm.get("collision_rebound_disabled") is True else "ENABLED",
            base_tone if xarm.get("collision_rebound_disabled") is True else "warn",
            fresh,
        ),
        _robot_metric(
            "CONTROL ENVELOPE",
            "READY" if xarm.get("control_envelope_ready") is True else "NOT READY",
            base_tone if xarm.get("control_envelope_ready") is True else "warn",
            fresh,
        ),
    ]

    tcp_min = safety_vectors["tcp_boundary_min_mm"]
    tcp_max = safety_vectors["tcp_boundary_max_mm"]
    boundary_text = "UNAVAILABLE"
    if tcp_min is not None and tcp_max is not None:
        boundary_text = "X %.0f..%.0f / Y %.0f..%.0f / Z %.0f..%.0f" % (
            tcp_min[0],
            tcp_max[0],
            tcp_min[1],
            tcp_max[1],
            tcp_min[2],
            tcp_max[2],
        )
    tcp_metrics = [
        _robot_metric(
            "TCP POSITION MM",
            _robot_vector_text(vectors["tcp_position_mm"], "", 1),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "TCP ORIENTATION DEG",
            _robot_vector_text(vectors["tcp_orientation_deg"], "", 1),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "TCP ORIENTATION RAD",
            _robot_vector_text(vectors["tcp_orientation_rad"], "", 2),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "TCP LOAD KG",
            _robot_number_text(controller_numbers["tcp_load_kg"], " KG", 2),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "CENTER OF GRAVITY MM",
            _robot_vector_text(controller_vectors["tcp_center_of_gravity_mm"], "", 1),
            base_tone,
            fresh,
        ),
        _robot_metric("TCP BOUNDARY MM", boundary_text, base_tone, fresh),
        # The current versioned backend contract does not expose measured TCP
        # velocity.  Keep the telemetry row explicit and neutral until a
        # distinct measured channel is added; a configured safety limit must
        # never masquerade as live speed.
        _robot_metric("TCP SPEED", "UNAVAILABLE", "muted", fresh),
        _robot_metric(
            "TCP MAX",
            _robot_number_text(safety_numbers["max_tcp_speed_mm_s"], " MM/S", 1),
            base_tone,
            fresh,
        ),
    ]

    joints_valid = all(
        vectors[name] is not None
        for name in (
            "joint_angles_deg",
            "joint_angles_rad",
            "joint_velocity_rad_s",
            "joint_effort",
        )
    )
    joint_metrics = []
    for index in range(6):
        if joints_valid:
            value = "%.1f DEG / %.2f RAD / %.3f RAD/S / SDK EFF %.2f" % (
                vectors["joint_angles_deg"][index],
                vectors["joint_angles_rad"][index],
                vectors["joint_velocity_rad_s"][index],
                vectors["joint_effort"][index],
            )
            joint_metrics.append(
                _robot_metric("J%d" % (index + 1), value, base_tone, fresh)
            )
        else:
            joint_metrics.append(
                _robot_metric("J%d" % (index + 1), "UNAVAILABLE", "muted", False)
            )

    lower = safety_vectors["joint_lower_rad"]
    upper = safety_vectors["joint_upper_rad"]
    limit_text = "UNAVAILABLE"
    if lower is not None and upper is not None:
        limit_text = " / ".join(
            "J%d %.2f..%.2f" % (index + 1, lower[index], upper[index])
            for index in range(6)
        )
    enable_text = (
        " / ".join(
            "J%d %s" % (i + 1, "ON" if value else "OFF")
            for i, value in enumerate(motor_enable)
        )
        if motor_enable is not None
        else "UNAVAILABLE"
    )
    brake_text = (
        " / ".join("J%d RAW%d" % (i + 1, value) for i, value in enumerate(motor_brake))
        if motor_brake is not None
        else "UNAVAILABLE"
    )
    controller_metrics = [
        _robot_metric(
            "FIRMWARE",
            _robot_version_text(controller.get("firmware_version")),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "AXIS",
            str(
                controller_integers["axis_count"]
                if controller_integers["axis_count"] is not None
                else "UNAVAILABLE"
            ),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "DEVICE",
            (
                "xARM LITE6 / TYPE 9"
                if controller_integers["axis_count"] == 6
                and controller_integers["device_type"] == 9
                else str(
                    controller_integers["device_type"]
                    if controller_integers["device_type"] is not None
                    else "UNAVAILABLE"
                )
            ),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "TEMPERATURE C",
            _robot_vector_text(controller_vectors["temperatures_c"], "", 1),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "SDK VOLTAGE",
            _robot_vector_text(controller_vectors["joint_voltages_v"], "", 1),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "SDK CURRENT",
            _robot_vector_text(controller_vectors["joint_currents_a"], "", 2),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "SDK TORQUE/CURRENT",
            _robot_vector_text(
                controller_vectors["joint_torque_or_current_sdk"], "", 2
            ),
            base_tone,
            fresh,
        ),
        _robot_metric("MOTOR ENABLE", enable_text, base_tone, fresh),
        _robot_metric("MOTOR BRAKE", brake_text, base_tone, fresh),
        _robot_metric(
            "COLLISION SENSITIVITY",
            str(
                controller_integers["collision_sensitivity"]
                if controller_integers["collision_sensitivity"] is not None
                else "UNAVAILABLE"
            ),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "TEACH SENSITIVITY",
            str(
                controller_integers["teach_sensitivity"]
                if controller_integers["teach_sensitivity"] is not None
                else "UNAVAILABLE"
            ),
            base_tone,
            fresh,
        ),
        _robot_metric(
            "JOINT SPEED",
            _robot_number_text(safety_numbers["max_joint_speed_rad_s"], " RAD/S", 3),
            base_tone,
            fresh,
        ),
        _robot_metric("JOINT LIMIT RAD", limit_text, base_tone, fresh),
    ]
    pages = [
        {"title": "STATUS", "metrics": status_metrics},
        {"title": "TCP", "metrics": tcp_metrics},
        {"title": "JOINTS", "metrics": joint_metrics},
        {"title": "CONTROLLER", "metrics": controller_metrics},
    ]
    return {"valid": True, "fresh": fresh, "page_count": 4, "pages": pages}


def _clock_text(time_module=time):
    now = time_module.localtime()
    return "%04d-%02d-%02d %02d:%02d:%02d" % (
        now[0],
        now[1],
        now[2],
        now[3],
        now[4],
        now[5],
    )


def _operation_message(value, limit=72):
    """Return bounded operator text while rejecting credential/path material."""

    text = _safe_text(value, limit)
    lowered = text.lower()
    if any(
        marker in lowered
        for marker in (
            "secret",
            "token",
            "password",
            "authorization",
            "http://",
            "https://",
            "../",
            "/etc/",
            "/var/",
        )
    ):
        return "Details withheld"
    return text


def _ota_history_view(value):
    """Reduce a bounded current-boot OTA transition history."""

    if not isinstance(value, list) or len(value) > 8:
        return ()
    allowed_states = {
        "idle",
        "checking",
        "up_to_date",
        "update_available",
        "busy",
        "pending_restart",
        "error",
        "unavailable",
    }
    rows = []
    previous_sequence = -1
    for raw in value:
        row = _mapping(raw)
        sequence = row.get("sequence")
        status = row.get("status")
        current_version = row.get("current_version")
        available_version = row.get("available_version")
        error_code = row.get("error_code")
        if (
            set(row)
            != {
                "sequence",
                "status",
                "current_version",
                "available_version",
                "error_code",
            }
            or isinstance(sequence, bool)
            or not isinstance(sequence, int)
            or not previous_sequence < sequence <= 1_000_000_000
            or status not in allowed_states
            or not isinstance(current_version, str)
            or not isinstance(available_version, str)
            or not isinstance(error_code, str)
            or _safe_text(current_version, 64) != current_version
            or _safe_text(available_version, 64) != available_version
            or _safe_text(error_code, 48) != error_code
        ):
            return ()
        rows.append(
            {
                "sequence": sequence,
                "status": status,
                "current_version": current_version,
                "available_version": available_version,
                "error_code": error_code,
            }
        )
        previous_sequence = sequence
    return tuple(rows)


def _operations_view(view):
    """Reduce every remaining documented operator workflow fail-closed."""

    view = _mapping(view)
    raw = _mapping(view.get("operations"))
    if raw.get("ui_schema_version") == 1:
        return raw
    schema_version = raw.get("schema_version")
    valid = schema_version in (1, 2)
    petri = _mapping(raw.get("petri")) if valid else {}
    recovery = _mapping(raw.get("recovery")) if valid else {}
    registration = _mapping(raw.get("registration")) if valid else {}
    datahub = _mapping(raw.get("datahub")) if valid else {}
    identity = _mapping(raw.get("identity")) if valid else {}
    review = _mapping(raw.get("manual_review")) if valid else {}
    history = _mapping(raw.get("history")) if valid else {}
    recipe = _mapping(raw.get("recipe")) if schema_version == 2 else {}
    preflight = _mapping(raw.get("preflight")) if schema_version == 2 else {}

    allowed_preflight_blockers = {
        "runtime_not_started",
        "runtime_fatal",
        "restart_pending",
        "recipe_not_selected",
        "tool_camera_not_ready",
        "workspace_camera_not_ready",
        "xarm_not_ready",
        "sampling_tool_not_ready",
        "datahub_not_ready",
        "site_safety_not_ready",
        "motion_release_incomplete",
        "motion_permit_not_ready",
        "motion_fault",
        "physical_operation_active",
        "supervised_recovery_required",
        "ota_active",
    }
    return _operations_view_continued(
        raw=raw,
        schema_version=schema_version,
        valid=valid,
        petri=petri,
        recovery=recovery,
        registration=registration,
        datahub=datahub,
        identity=identity,
        review=review,
        history=history,
        recipe=recipe,
        preflight=preflight,
        allowed_preflight_blockers=allowed_preflight_blockers,
    )


def _production_view(view, operations=None):
    """Compose the #327 screen exclusively from sanitized local status."""

    view = _mapping(view)
    operations = (
        _operations_view({"operations": operations})
        if isinstance(operations, dict)
        else _operations_view(view)
    )
    petri = _mapping(operations.get("petri"))
    recipe = _mapping(operations.get("recipe"))
    preflight = _mapping(operations.get("preflight"))
    components = _mapping(preflight.get("components"))
    recovery = _mapping(operations.get("recovery"))
    datahub = _mapping(operations.get("datahub"))
    ota = _mapping(view.get("ota"))
    history = operations.get("ota_history")
    history = history if isinstance(history, tuple) else ()
    blockers = preflight.get("blockers")
    blockers = blockers if isinstance(blockers, tuple) else ("runtime_fatal",)
    contract_valid = bool(
        view.get("health_authoritative") is True and operations.get("valid") is True
    )
    if not contract_valid:
        blockers = ("runtime_not_started",)
        components = {
            name: "blocked"
            for name in (
                "xarm",
                "tool_camera",
                "workspace_camera",
                "sampling_tool",
                "datahub",
                "site_safety",
                "motion_permit",
                "ota",
            )
        }
    blockers_text = (
        " / ".join(value.replace("_", " ").upper() for value in blockers[:3])
        if blockers
        else "ALL BACKEND CHECKS READY"
    )
    recipe_text = "NO RECIPE SELECTED"
    if recipe.get("selected") is True:
        recipe_text = "%s  V%s  [%s]" % (
            _safe_text(recipe.get("recipe_id") or "--", 32),
            _safe_text(recipe.get("recipe_version") or "--", 20),
            _safe_text(recipe.get("process_profile_sha256") or "", 8),
        )
    run_id = _safe_text(petri.get("run_id") or "--", 10)
    plate_id = _safe_text(petri.get("current_plate_id") or "--", 32)
    process_state = _safe_text(petri.get("process_state") or "FAULT_LOCKED", 28)
    start_allowed = bool(
        contract_valid
        and preflight.get("ready") is True
        and petri.get("action_allowed") is True
        and petri.get("state")
        in ("ready", "confirming", "completed", "cancelled", "error")
    )
    stop_required = bool(
        operations.get("stop_allowed") is True
        or petri.get("stop_allowed") is True
        or recovery.get("stop_allowed") is True
    )
    hardware_ready = all(
        contract_valid and components.get(name) == "ready"
        for name in ("xarm", "tool_camera", "workspace_camera", "sampling_tool")
    )
    latest_ota = history[-1] if history else {}
    return {
        "valid": contract_valid,
        "ready": bool(contract_valid and preflight.get("ready") is True),
        "blockers": tuple(blockers),
        "blockers_text": _safe_text(blockers_text, 120),
        "recipe": _safe_text(recipe_text, 96),
        "petri": {
            "state": _safe_text(petri.get("state") or "error", 18).upper(),
            "process_state": process_state,
            "run_id": run_id,
            "plate_id": plate_id,
            "progress": min(max(int(petri.get("progress") or 0), 0), 100),
            "steps": _safe_text(petri.get("steps") or "0 / 0 SCHRITTE", 36),
            "eta": _safe_text(petri.get("eta") or "ETA 0 S", 24),
            "message": _safe_text(petri.get("message") or "--", 72),
            "start_allowed": start_allowed,
            "stop_required": stop_required,
            "button": (
                "SOFTWARE STOP"
                if stop_required
                else (
                    "NOCHMAL BESTAETIGEN"
                    if petri.get("state") == "confirming" and start_allowed
                    else "PRODUKTION START" if start_allowed else "GESPERRT"
                )
            ),
            "tone": (
                "danger"
                if stop_required or petri.get("recovery_required") is True
                else "ok" if start_allowed else "warn"
            ),
        },
        "hardware": {
            "ready": hardware_ready,
            "detail": "XARM %s | CAM T %s W %s | TOOL %s"
            % (
                str(components.get("xarm") or "blocked").upper(),
                str(components.get("tool_camera") or "blocked").upper(),
                str(components.get("workspace_camera") or "blocked").upper(),
                str(components.get("sampling_tool") or "blocked").upper(),
            ),
            "tone": "ok" if hardware_ready else "danger",
        },
        "datahub": {
            "status": _safe_text(datahub.get("status") or "NOT CONFIGURED", 40),
            "detail": "PENDING %d | DEAD %d | BINDING %s"
            % (
                int(datahub.get("pending") or 0),
                int(datahub.get("dead") or 0),
                "VERIFIED" if datahub.get("bound") is True else "BLOCKED",
            ),
            "tone": _safe_text(datahub.get("tone") or "muted", 12),
        },
        "recovery": {
            "state": _safe_text(recovery.get("state") or "error", 20).upper(),
            "detail": _safe_text(recovery.get("message") or "--", 80),
            "action_allowed": recovery.get("action_allowed") is True,
            "stop_required": recovery.get("stop_allowed") is True,
            "button": _safe_text(recovery.get("button") or "GESPERRT", 28),
            "tone": _safe_text(recovery.get("tone") or "muted", 12),
        },
        "ota": {
            "status": _safe_text(ota.get("status") or "unavailable", 24).upper(),
            "detail": "CURRENT %s | AVAILABLE %s | HISTORY %d | LAST %s"
            % (
                _safe_text(ota.get("current_version") or "--", 24),
                _safe_text(ota.get("available_version") or "--", 24),
                len(history),
                _safe_text(_mapping(latest_ota).get("status") or "--", 20).upper(),
            ),
            "tone": _safe_text(ota.get("tone") or "muted", 12),
        },
    }


def _operations_view_continued(
    *,
    raw,
    schema_version,
    valid,
    petri,
    recovery,
    registration,
    datahub,
    identity,
    review,
    history,
    recipe,
    preflight,
    allowed_preflight_blockers,
):
    component_names = {
        "xarm",
        "tool_camera",
        "workspace_camera",
        "sampling_tool",
        "datahub",
        "site_safety",
        "motion_permit",
        "ota",
    }
    components = _mapping(preflight.get("components"))
    blockers = preflight.get("blockers")
    recipe_valid = bool(
        schema_version == 2
        and set(recipe)
        == {
            "selected",
            "recipe_id",
            "recipe_version",
            "process_profile_sha256",
        }
        and isinstance(recipe.get("selected"), bool)
        and isinstance(recipe.get("recipe_id"), str)
        and len(recipe.get("recipe_id")) <= 64
        and isinstance(recipe.get("recipe_version"), str)
        and len(recipe.get("recipe_version")) <= 32
        and isinstance(recipe.get("process_profile_sha256"), str)
        and (
            not recipe.get("selected")
            or (
                bool(recipe.get("recipe_id"))
                and bool(recipe.get("recipe_version"))
                and _lower_hex_exact(recipe.get("process_profile_sha256"), 64)
            )
        )
    )
    preflight_valid = bool(
        schema_version == 2
        and set(preflight)
        == {
            "read_only",
            "ready",
            "motion_permit_required",
            "motion_permit_ready",
            "blockers",
            "components",
        }
        and preflight.get("read_only") is True
        and isinstance(preflight.get("ready"), bool)
        and preflight.get("motion_permit_required") is True
        and isinstance(preflight.get("motion_permit_ready"), bool)
        and isinstance(blockers, list)
        and len(blockers) <= len(allowed_preflight_blockers)
        and len(set(blockers)) == len(blockers)
        and all(value in allowed_preflight_blockers for value in blockers)
        and set(components) == component_names
        and all(value in ("ready", "blocked") for value in components.values())
        and (preflight.get("ready") is (not blockers))
        and (
            preflight.get("motion_permit_ready")
            is (components.get("motion_permit") == "ready")
        )
    )
    if not recipe_valid:
        recipe = {
            "selected": False,
            "recipe_id": "",
            "recipe_version": "",
            "process_profile_sha256": "",
        }
    if not preflight_valid:
        blockers = ["runtime_fatal"]
        components = {name: "blocked" for name in component_names}
        preflight = {
            "read_only": True,
            "ready": False,
            "motion_permit_required": True,
            "motion_permit_ready": False,
            "blockers": blockers,
            "components": components,
        }
    if schema_version == 2 and (not recipe_valid or not preflight_valid):
        valid = False

    petri_states = (
        "unavailable",
        "ready",
        "confirming",
        "starting",
        "running",
        "stopping",
        "completed",
        "cancelled",
        "error",
    )
    recovery_states = (
        "unavailable",
        "idle",
        "confirming",
        "starting",
        "running",
        "stopping",
        "completed",
        "error",
    )
    petri_state = petri.get("state") if petri.get("state") in petri_states else "error"
    recovery_state = (
        recovery.get("state") if recovery.get("state") in recovery_states else "error"
    )

    def count(source, name, maximum=1_000_000_000):
        value = source.get(name)
        if isinstance(value, bool) or not isinstance(value, int):
            return 0
        return value if 0 <= value <= maximum else 0

    total = count(petri, "total_steps", 10_000)
    completed = min(count(petri, "completed_steps", 10_000), total or 10_000)
    progress = count(petri, "progress_percent", 100)
    eta = petri.get("eta_seconds")
    if (
        isinstance(eta, bool)
        or not isinstance(eta, (int, float))
        or not 0 <= eta <= 86_400
    ):
        eta = 0

    process_states = {
        "IDLE",
        "PREFLIGHT",
        "AUTHORIZED",
        "HOME",
        "LOCATE_TRAY",
        "IDENTIFY_PLATES",
        "APPROACH",
        "PICK_LID",
        "VERIFY_GRASP",
        "CAPTURE",
        "RETURN_LID",
        "VERIFY_RELEASE",
        "NEXT_PLATE",
        "RETURN_HOME",
        "LOCAL_COMMIT",
        "QUEUE_UPLOAD",
        "COMPLETE",
        "STOPPING",
        "CANCELLED",
        "FAULT_LOCKED",
        "RECOVERY_REQUIRED",
    }
    process_state = petri.get("process_state")
    if process_state not in process_states:
        process_state = "FAULT_LOCKED" if schema_version == 2 else "IDLE"
    run_id = petri.get("run_id")
    if not isinstance(run_id, str) or (run_id and not _lower_hex_exact(run_id, 32)):
        run_id = ""
    current_plate_id = petri.get("current_plate_id")
    if (
        not isinstance(current_plate_id, str)
        or len(current_plate_id) > 64
        or _safe_text(current_plate_id, 64) != current_plate_id
    ):
        current_plate_id = ""

    petri_active = petri_state in ("starting", "running", "stopping")
    recovery_active = recovery_state in ("starting", "running", "stopping")
    petri_configured = petri.get("configured") is True
    recovery_configured = recovery.get("configured") is True
    petri_action_allowed = bool(
        petri_configured
        and petri.get("action_allowed") is True
        and petri_state in ("ready", "confirming", "completed", "cancelled", "error")
    )
    recovery_action_allowed = bool(
        recovery_configured
        and recovery.get("action_allowed") is True
        and recovery_state in ("idle", "confirming", "completed", "error")
    )
    if petri_active:
        petri_tone = "danger"
        petri_button = "SOFTWARE STOP"
    elif petri_state == "confirming":
        petri_tone = "warn"
        petri_button = "NOCHMAL BESTAETIGEN"
    elif petri_action_allowed:
        petri_tone = "ok"
        petri_button = "PETRI START"
    elif petri_state == "error":
        petri_tone = "danger"
        petri_button = "GESPERRT"
    else:
        petri_tone = "muted"
        petri_button = "NICHT VERFUEGBAR"

    if recovery_active:
        recovery_tone = "danger"
        recovery_button = "SOFTWARE STOP"
    elif recovery_state == "confirming":
        recovery_tone = "warn"
        recovery_button = "NOCHMAL BESTAETIGEN"
    elif recovery_action_allowed:
        recovery_tone = "warn"
        recovery_button = "RECOVERY START"
    elif recovery_state == "error":
        recovery_tone = "danger"
        recovery_button = "PRUEFUNG ERFORDERLICH"
    else:
        recovery_tone = "muted"
        recovery_button = "NICHT VERFUEGBAR"

    registration_status = (
        registration.get("status")
        if registration.get("status")
        in ("off", "pending", "verified", "incomplete", "error")
        else "error"
    )
    registration_tone = (
        "ok"
        if registration.get("ready") is True and registration_status == "verified"
        else "danger" if registration_status == "error" else "warn"
    )
    registration_configured = registration.get("configured") is True
    registration_action_allowed = bool(
        registration_configured
        and registration.get("action_allowed") is True
        and registration_status in ("off", "pending", "verified", "incomplete", "error")
    )
    datahub_available = datahub.get("available") is True
    datahub_configured = datahub.get("configured") is True
    datahub_bound = datahub.get("dataset_binding_verified") is True
    pending = count(datahub, "pending")
    dead = count(datahub, "dead_letters")
    datahub_tone = (
        "danger"
        if dead
        else (
            "ok"
            if datahub_available and datahub_bound
            else "warn" if datahub_configured else "muted"
        )
    )
    identity_configured = identity.get("configured") is True
    identity_state = _safe_text(identity.get("state") or "unavailable", 28).lower()
    if identity_state not in (
        "registry_ready",
        "registry_error",
        "scanner_unavailable",
    ):
        identity_state = (
            "registry_error" if identity_configured else "scanner_unavailable"
        )
    review_configured = review.get("configured") is True
    review_pending = count(review, "pending", 100_000)
    review_state = _safe_text(review.get("state") or "unavailable", 24).lower()
    if review_state not in (
        "pending",
        "ready",
        "idle",
        "error",
        "unavailable",
        "confirming",
    ):
        review_state = "error"
    review_action_allowed = bool(
        review_configured
        and review_pending > 0
        and review.get("action_allowed") is True
        and review_state in ("pending", "ready", "confirming")
    )
    identity_tone = (
        "danger"
        if identity_state == "registry_error" or review_state == "error"
        else (
            "warn"
            if review_pending > 0
            else (
                "ok"
                if identity_configured
                and identity_state == "registry_ready"
                and review_configured
                else "muted"
            )
        )
    )
    history_configured = history.get("configured") is True
    history_records_value = history.get("records")
    history_records_valid = bool(
        isinstance(history_records_value, int)
        and not isinstance(history_records_value, bool)
        and 0 <= history_records_value <= 1_000_000_000
    )
    recent_raw = history.get("recent")
    recent_valid = isinstance(recent_raw, list) and len(recent_raw) <= 20
    recent_rows = []
    allowed_identifier = (
        "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_.:+-"
    )
    if recent_valid:
        for row in recent_raw:
            row = _mapping(row)
            observation_id = row.get("observation_id")
            cluster_id = row.get("cluster_id")
            plate_id = row.get("plate_id")
            captured_at = row.get("captured_at")
            area = _bounded_number(row.get("area_px2"), maximum=1e12)
            confidence = _bounded_number(
                row.get("confidence"), minimum=0.0, maximum=1.0
            )
            row_state = row.get("status")
            selected = row.get("selected")
            identifiers = (
                (observation_id, 120),
                (cluster_id, 120),
                (plate_id, 64),
            )
            if (
                not row
                or any(
                    not isinstance(value, str)
                    or not value
                    or len(value) > limit
                    or any(character not in allowed_identifier for character in value)
                    for value, limit in identifiers
                )
                or not isinstance(captured_at, str)
                or not captured_at
                or len(captured_at) > 64
                or _safe_text(captured_at, 64) != captured_at
                or "/" in captured_at
                or "\\" in captured_at
                or area is None
                or confidence is None
                or row_state
                not in ("accepted_auto", "requires_review", "accepted_manual")
                or not isinstance(selected, bool)
                or (row_state == "requires_review" and selected is not False)
                or (row_state == "accepted_manual" and selected is not True)
            ):
                recent_valid = False
                recent_rows = []
                break
            recent_rows.append(
                {
                    "plate_id": plate_id,
                    "status": row_state,
                    "captured_at": captured_at,
                }
            )
    history_contract_valid = bool(
        not history_configured
        or (
            history_records_valid
            and recent_valid
            and isinstance(history.get("export_available"), bool)
        )
    )
    latest_history = "--"
    if recent_rows:
        latest_history = "%s / %s" % (
            recent_rows[0]["status"].upper(),
            recent_rows[0]["plate_id"],
        )

    return {
        "ui_schema_version": 1,
        "valid": valid,
        "stop_allowed": bool(
            petri.get("stop_allowed") is True
            or recovery.get("stop_allowed") is True
            or petri_active
            or recovery_active
        ),
        "petri": {
            "configured": petri_configured,
            "state": petri_state,
            "action_allowed": petri_action_allowed,
            "stop_allowed": petri.get("stop_allowed") is True or petri_active,
            "progress": progress,
            "steps": "%d / %d SCHRITTE" % (completed, total),
            "eta": "ETA %d S" % int(eta),
            "message": _operation_message(petri.get("message")) or "--",
            "error_code": _operation_message(petri.get("error_code"), 32),
            "tone": petri_tone,
            "button": petri_button,
            "process_state": process_state,
            "run_id": run_id,
            "current_plate_id": current_plate_id,
            "transition_sequence": count(petri, "transition_sequence", 1_000_000),
            "local_evidence_committed": (petri.get("local_evidence_committed") is True),
            "upload_queued": petri.get("upload_queued") is True,
            "recovery_required": petri.get("recovery_required") is True,
        },
        "recipe": dict(recipe),
        "preflight": {
            "read_only": True,
            "ready": preflight.get("ready") is True,
            "motion_permit_required": True,
            "motion_permit_ready": preflight.get("motion_permit_ready") is True,
            "blockers": tuple(blockers),
            "components": dict(components),
        },
        "ota_history": _ota_history_view(raw.get("ota_history")),
        "recovery": {
            "configured": recovery_configured,
            "state": recovery_state,
            "action_allowed": recovery_action_allowed,
            "stop_allowed": recovery.get("stop_allowed") is True or recovery_active,
            "message": _operation_message(recovery.get("message")) or "--",
            "error_code": _operation_message(recovery.get("error_code"), 32),
            "tone": recovery_tone,
            "button": recovery_button,
        },
        "registration": {
            "configured": registration_configured,
            "ready": registration.get("ready") is True,
            "status": registration_status.upper(),
            "action_allowed": registration_action_allowed,
            "tone": registration_tone,
        },
        "datahub": {
            "configured": datahub_configured,
            "available": datahub_available,
            "bound": datahub_bound,
            "pending": pending,
            "dead": dead,
            "status": (
                "BOUND / %d PENDING" % pending
                if datahub_available and datahub_bound
                else "NOT CONFIGURED" if not datahub_configured else "CHECK BINDING"
            ),
            "tone": datahub_tone,
        },
        "identity": {
            "configured": identity_configured,
            "state": identity_state.upper(),
            "action_allowed": bool(
                identity_configured
                and identity_state == "registry_ready"
                and identity.get("action_allowed") is True
            ),
            "plates": count(identity, "plates", 1_000_000),
            "tone": identity_tone,
        },
        "review": {
            "configured": review_configured,
            "pending": review_pending,
            "action_allowed": review_action_allowed,
            "state": review_state.upper(),
        },
        "history": {
            "configured": history_configured,
            "valid": history_contract_valid,
            "records": history_records_value if history_records_valid else 0,
            "export_available": bool(
                history_contract_valid and history.get("export_available") is True
            ),
            "recent": len(recent_rows) if history_contract_valid else 0,
            "latest": _safe_text(latest_history, 96),
            "tone": (
                "danger"
                if history_configured and not history_contract_valid
                else "ok" if history_configured else "muted"
            ),
        },
    }


_TENANT_AUTH_KEYS = (
    "schema_version",
    "configured",
    "state",
    "tenant_url",
    "tenant",
    "username",
    "display_name",
    "access_expires_in",
    "refresh_expires_in",
    "session_persisted",
    "last_error",
)


def _tenant_auth_view(runtime):
    """Reduce the secret-free mobile-session status for display."""

    raw_value = _mapping(runtime).get("tenant_auth")
    if not isinstance(raw_value, dict) or set(raw_value) != set(_TENANT_AUTH_KEYS):
        return {
            "valid": False,
            "configured": False,
            "state": "unavailable",
            "tenant_url": "",
            "tenant": "",
            "username": "",
            "display_name": "",
            "access_expires_in": 0,
            "refresh_expires_in": 0,
            "session_persisted": False,
            "last_error": "contract_invalid",
            "status": "UNAVAILABLE",
            "tone": "muted",
        }
    raw = dict(raw_value)
    state = raw.get("state")
    if (
        raw.get("schema_version") != 1
        or not isinstance(raw.get("configured"), bool)
        or state
        not in (
            "logged_out",
            "authenticated",
            "refresh_required",
            "expired",
            "error",
            "unavailable",
        )
        or not all(
            isinstance(raw.get(key), str)
            for key in (
                "tenant_url",
                "tenant",
                "username",
                "display_name",
                "last_error",
            )
        )
        or len(raw["tenant_url"]) > 512
        or len(raw["tenant"]) > 128
        or len(raw["username"]) > 254
        or len(raw["display_name"]) > 254
        or len(raw["last_error"]) > 64
        or not isinstance(raw.get("session_persisted"), bool)
    ):
        return _tenant_auth_view({})
    lifetimes = []
    for key in ("access_expires_in", "refresh_expires_in"):
        value = raw.get(key)
        if (
            isinstance(value, bool)
            or not isinstance(value, int)
            or not 0 <= value <= 31_536_000
        ):
            return _tenant_auth_view({})
        lifetimes.append(value)
    if state in ("authenticated", "refresh_required"):
        if not raw["tenant_url"] or not raw["tenant"] or not raw["username"]:
            return _tenant_auth_view({})
    elif state == "logged_out" and any(
        raw[key] for key in ("tenant_url", "tenant", "username", "display_name")
    ):
        return _tenant_auth_view({})
    status_tones = {
        "authenticated": ("SIGNED IN", "ok"),
        "refresh_required": ("REFRESH", "warn"),
        "logged_out": ("LOGIN", "muted"),
        "expired": ("EXPIRED", "warn"),
        "error": ("CHECK", "danger"),
        "unavailable": ("UNAVAILABLE", "muted"),
    }
    status, tone = status_tones[state]
    return {
        "valid": True,
        "configured": raw["configured"],
        "state": state,
        "tenant_url": _safe_text(raw["tenant_url"], 96),
        "tenant": _safe_text(raw["tenant"], 64),
        "username": _safe_text(raw["username"], 64),
        "display_name": _safe_text(raw["display_name"], 64),
        "access_expires_in": lifetimes[0],
        "refresh_expires_in": lifetimes[1],
        "session_persisted": raw["session_persisted"],
        "last_error": _safe_text(raw["last_error"], 64),
        "status": status,
        "tone": tone,
    }


LAUNCHER_ITEMS = (
    ("tool", "01", "VIDEOSTREAM 1"),
    ("workspace", "02", "VIDEOSTREAM 2"),
    ("system", "03", "xARM + SYSTEM\nCONTROL"),
    ("capture", "04", "CAPTURE +\nDATAHUB"),
    ("updates", "05", "SYSTEM UPDATE"),
    ("metrics", "06", "SYSTEM METRICS"),
    ("digital_twin", "07", "3D DIGITAL TWIN"),
    ("workspace_teach", "08", "WORKSPACE CONFIG"),
    ("tenant_auth", "09", "TENANT LOGIN"),
    ("hand_training", "10", "HAND TRAINING"),
    ("production", "11", "AINA PRODUCTION"),
)


def _launcher_view(view):
    """Return the bounded, secret-free launcher button states.

    The launcher is navigation only.  In particular, the system destination
    never arms or moves the xArm and the capture destination fails closed when
    the backend does not expose the hardened capture contract.
    """

    view = _mapping(view)
    cameras = _mapping(view.get("cameras"))
    tool = _mapping(cameras.get("tool"))
    workspace = _mapping(cameras.get("workspace"))
    motion = _mapping(view.get("motion"))
    xarm = _mapping(view.get("xarm"))
    capture = _mapping(view.get("capture"))
    ota = _mapping(view.get("ota"))
    digital_twin = _mapping(view.get("digital_twin"))
    workspace_teach = _mapping(view.get("workspace_teach"))
    workspace_boundary = _mapping(view.get("workspace_boundary"))
    tenant_auth = _mapping(view.get("tenant_auth"))
    hand_training = _mapping(view.get("hand_training"))
    operations = _operations_view(view)
    search = _motion_search_view(view)
    xarm_system_check_ok = bool(
        xarm.get("system_check_ok") is True
        and xarm.get("configured") is True
        and xarm.get("connected") is True
        and xarm.get("healthy") is True
        and xarm.get("fresh") is True
        and xarm.get("error_code") == 0
        and xarm.get("warning_code") == 0
    )

    def camera_state(camera):
        if camera.get("healthy") is True:
            return {"enabled": True, "status": "LIVE", "tone": "ok"}
        return {
            "enabled": True,
            "status": "CHECK",
            "tone": _safe_text(camera.get("tone") or "warn", 12),
        }

    capture_configured = capture.get("configured") is True
    if not capture_configured:
        capture_status = "UNAVAILABLE"
        capture_tone = "muted"
    elif capture.get("stop_allowed") is True:
        capture_status = "RUNNING"
        capture_tone = "danger"
    elif capture.get("action_allowed") is True:
        capture_status = "READY"
        capture_tone = "ok"
    else:
        capture_status = "CHECK"
        capture_tone = _safe_text(capture.get("tone") or "warn", 12)

    ota_status = _safe_text(ota.get("status") or "unavailable", 14)
    if ota.get("action_allowed") is True:
        ota_status = "RETRY" if ota_status == "error" else "READY"
    elif ota_status == "pending_restart":
        ota_status = "RESTART"
    elif ota_status in ("checking", "busy"):
        ota_status = "CHECKING"
    elif ota_status == "up_to_date":
        ota_status = "CURRENT"
    else:
        ota_status = "CHECK"

    return {
        "tool": camera_state(tool),
        "workspace": camera_state(workspace),
        "system": {
            "enabled": True,
            # Button 3 is a real bounded control destination.  Make a
            # commissioned action visible as READY rather than labelling the
            # closed pre-motion safety gate as though no control existed.
            "status": (
                "STOP"
                if search.get("stop_allowed") is True
                else (
                    "READY"
                    if search.get("action_allowed") is True
                    else ("CHECK OK" if xarm_system_check_ok else "CHECK")
                )
            ),
            "tone": (
                "danger"
                if search.get("stop_allowed") is True
                else (
                    "ok"
                    if search.get("action_allowed") is True or xarm_system_check_ok
                    else (
                        "danger"
                        if motion.get("tone") == "danger"
                        or xarm.get("tone") == "danger"
                        else "warn"
                    )
                )
            ),
        },
        "capture": {
            # Navigation remains available so the operator can see why a run
            # is blocked.  The guarded action control stays disabled.
            "enabled": True,
            "status": capture_status,
            "tone": capture_tone,
        },
        "updates": {
            "enabled": True,
            "status": ota_status,
            "tone": _safe_text(ota.get("tone") or "muted", 12),
        },
        "metrics": {
            "enabled": True,
            "status": "LIVE" if view.get("ready") is True else "CHECK",
            "tone": _safe_text(view.get("tone") or "warn", 12),
        },
        "digital_twin": {
            "enabled": True,
            "status": _safe_text(
                digital_twin.get("status") or "UNAVAILABLE",
                14,
            ),
            "tone": _safe_text(digital_twin.get("tone") or "muted", 12),
        },
        "workspace_teach": {
            "enabled": True,
            "status": _safe_text(
                (
                    workspace_boundary.get("status")
                    if workspace_boundary.get("configured") is True
                    else workspace_teach.get("status")
                )
                or "UNAVAILABLE",
                14,
            ),
            "tone": _safe_text(
                (
                    workspace_boundary.get("tone")
                    if workspace_boundary.get("configured") is True
                    else workspace_teach.get("tone")
                )
                or "muted",
                12,
            ),
        },
        "tenant_auth": {
            "enabled": True,
            "status": _safe_text(tenant_auth.get("status") or "UNAVAILABLE", 14),
            "tone": _safe_text(tenant_auth.get("tone") or "muted", 12),
        },
        "hand_training": {
            "enabled": True,
            "status": _safe_text(
                (
                    "RECORDING"
                    if hand_training.get("active") is True
                    else "READY"
                    if hand_training.get("start_allowed") is True
                    else hand_training.get("state")
                )
                or "UNAVAILABLE",
                14,
            ).upper(),
            "tone": (
                "danger"
                if hand_training.get("active") is True
                else "ok"
                if hand_training.get("start_allowed") is True
                else "warn"
                if hand_training.get("configured") is True
                else "muted"
            ),
        },
        "production": {
            "enabled": True,
            "status": (
                "STOP"
                if operations.get("stop_allowed") is True
                else (
                    "RUNNING"
                    if _mapping(operations.get("petri")).get("state")
                    in ("starting", "running", "stopping")
                    else (
                        "READY"
                        if _mapping(operations.get("preflight")).get("ready") is True
                        else "LOCKED"
                    )
                )
            ),
            "tone": (
                "danger"
                if operations.get("stop_allowed") is True
                else (
                    "ok"
                    if _mapping(operations.get("preflight")).get("ready") is True
                    else "warn"
                )
            ),
        },
    }


def _system_control_view(view):
    """Reduce xArm health and the one reviewed camera-guided search action."""

    view = _mapping(view)
    xarm = _mapping(view.get("xarm"))
    motion = _mapping(view.get("motion"))
    capture = _mapping(view.get("capture"))
    search = _motion_search_view(view)
    safety = _safety_configuration_view(view)
    # Motion-ready is an admission gate, not an active-motion invariant.
    # Once the reviewed search owns motion, `moving=True` is expected and must
    # never overwrite the active state or hide the universal STOP route.
    if search.get("state") not in ("armed_live", "fault_locked", "busy") and (
        xarm.get("motion_ready") is not True or xarm.get("moving") is True
    ):
        search = dict(search)
        system_check_ok = bool(
            xarm.get("system_check_ok") is True
            and xarm.get("configured") is True
            and xarm.get("connected") is True
            and xarm.get("healthy") is True
            and xarm.get("fresh") is True
            and xarm.get("error_code") == 0
            and xarm.get("warning_code") == 0
        )
        search.update(
            {
                "action_allowed": False,
                "state": "locked",
                "tone": (
                    "warn"
                    if system_check_ok
                    else "danger" if xarm.get("tone") == "danger" else "warn"
                ),
                "headline": (
                    "ROBOT CONTROL SETUP REQUIRED"
                    if system_check_ok
                    else "xARM SAFETY-GATE GESPERRT"
                ),
                "detail": (
                    "System check OK; motion safeguards are not ready"
                    if system_check_ok
                    else "Frische fehlerfreie Telemetrie und Stillstand erforderlich"
                ),
                "button": (
                    "SEARCH PATH START" if system_check_ok else "SEARCH PATH START"
                ),
                "request_allowed": True,
            }
        )
    stop_allowed = bool(
        capture.get("stop_allowed") is True
        or search.get("state") in ("armed_live", "fault_locked")
    )
    safety_setup_required = bool(
        safety.get("valid") is not True or safety.get("configured") is not True
    )
    safety_setup_route_allowed = bool(
        safety_setup_required
        and xarm.get("system_check_ok") is True
        and xarm.get("moving") is False
    )
    search_preflight_allowed = bool(
        safety.get("valid") is True
        and safety.get("configured") is True
        and safety.get("exact_readback") is True
        and xarm.get("configured") is True
        and xarm.get("connected") is True
        and xarm.get("healthy") is True
        and xarm.get("fresh") is True
        and xarm.get("error_code") == 0
        and xarm.get("warning_code") == 0
        and xarm.get("system_check_ok") is True
        and xarm.get("moving") is False
        and search.get("request_allowed") is True
    )
    if stop_allowed:
        action = "SOFTWARE STOP"
        action_detail = "Alle lokalen Bewegungs-Owner sofort verriegeln"
        action_tone = "danger"
    elif safety_setup_required:
        action = "SAFETY SETUP >"
        action_detail = "Pinned Profil pruefen und Controller-Readback bestaetigen"
        action_tone = "warn" if safety_setup_route_allowed else "danger"
    elif search.get("action_allowed") is True:
        action = search["button"]
        action_detail = search["detail"]
        action_tone = "ok"
    elif search_preflight_allowed:
        action = "SEARCH GATES PRUEFEN"
        action_detail = "Exakten Backend-Preflight ohne Bewegungsfreigabe anfordern"
        action_tone = "warn"
    else:
        action = "SEARCH GESPERRT"
        action_detail = "Weitere Search-Gates sind noch nicht freigegeben"
        action_tone = search["tone"]

    if capture.get("configured") is not True:
        capture_gate = "CAPTURE NICHT KONFIGURIERT"
        capture_detail = "Capture + DataHub nicht konfiguriert"
        capture_tone = "muted"
    elif stop_allowed:
        capture_gate = "SOFTWARE STOP READY"
        capture_detail = "Aktiver Lauf; STOP bleibt erreichbar"
        capture_tone = "danger"
    elif capture.get("action_allowed") is True:
        capture_gate = "CAPTURE GATE READY"
        capture_detail = "Hardened 15 s / 1 Hz Lauf kann geprueft werden"
        capture_tone = "ok"
    else:
        capture_gate = "CAPTURE GATE BLOCKED"
        capture_detail = _safe_text(capture.get("detail") or "Freigabe fehlt", 72)
        capture_tone = _safe_text(capture.get("tone") or "warn", 12)

    return {
        "xarm_headline": _safe_text(xarm.get("summary") or "UNAVAILABLE", 32),
        "xarm_detail": _safe_text(xarm.get("detail") or "No telemetry", 72),
        "xarm_guidance": _safe_text(
            xarm.get("guidance") or "Robot readiness is not verified.", 96
        ),
        "xarm_tone": _safe_text(xarm.get("tone") or "muted", 12),
        "motion_gate": _safe_text(motion.get("badge") or "NOT VERIFIED", 28),
        "motion_detail": _safe_text(
            motion.get("policy") or "Runtime motion gate unavailable", 72
        ),
        "motion_tone": _safe_text(motion.get("tone") or "muted", 12),
        "capture_gate": capture_gate,
        "capture_detail": capture_detail,
        "capture_tone": capture_tone,
        "route_allowed": bool(
            stop_allowed
            or safety_setup_route_allowed
            or safety.get("search_ready") is True
            or search_preflight_allowed
        ),
        "safety_setup_required": safety_setup_route_allowed,
        "safety_valid": safety.get("valid") is True,
        "safety_configured": safety.get("configured") is True,
        "search_action_allowed": bool(
            safety.get("search_ready") is True and search.get("action_allowed") is True
        ),
        "search_request_allowed": search_preflight_allowed,
        "stop_allowed": stop_allowed,
        "action": action,
        "action_detail": action_detail,
        "action_tone": action_tone,
        "search_review": search["review"],
        "search_progress": search["workflow_progress"],
        "search_stage": search["workflow_stage"],
    }


def _metrics_view(view):
    """Return bounded operator metrics backed by versioned diagnostics data."""

    view = _mapping(view)
    motion = _mapping(view.get("motion"))
    xarm = _mapping(view.get("xarm"))
    capture = _mapping(view.get("capture"))
    ota = _mapping(view.get("ota"))
    diagnostics = _diagnostics_view(view)
    system = diagnostics["system"]
    uptime = system.get("uptime_seconds")
    if uptime is None:
        uptime_text = "--"
    elif uptime < 3600:
        uptime_text = "%d M" % int(uptime / 60)
    elif uptime < 86400:
        uptime_text = "%.1f H" % (uptime / 3600.0)
    else:
        uptime_text = "%.1f D" % (uptime / 86400.0)
    try:
        camera_count = int(view.get("camera_count") or 0)
    except (TypeError, ValueError):
        camera_count = 0
    if capture.get("configured") is True:
        capture_metric = (
            _safe_text(capture.get("state") or "UNKNOWN", 20).upper(),
            _safe_text(capture.get("tone") or "warn", 12),
        )
        dataset_metric = (
            _safe_text(capture.get("dataset_state") or "UNKNOWN", 20).upper(),
            _safe_text(capture.get("dataset_tone") or "warn", 12),
        )
    else:
        capture_metric = ("NOT CONFIGURED", "muted")
        dataset_metric = ("NOT CONFIGURED", "muted")
    load = system.get("load_1m")
    cores = system.get("cpu_cores") or 0
    if load is None or cores <= 0:
        cpu_metric = ("UNAVAILABLE", "muted")
    else:
        ratio = load / float(cores)
        cpu_metric = (
            "LOAD %.2f / %d C" % (load, cores),
            "danger" if ratio >= 1.5 else "warn" if ratio >= 0.8 else "ok",
        )
    memory_total = system.get("memory_total") or 0
    memory_available = system.get("memory_available") or 0
    if memory_total <= 0 or memory_available > memory_total:
        memory_metric = ("UNAVAILABLE", "muted")
    else:
        used_percent = int(100 * (memory_total - memory_available) / memory_total)
        memory_metric = (
            "RAM %d%%" % used_percent,
            "danger" if used_percent >= 95 else "warn" if used_percent >= 85 else "ok",
        )
    disk_total = system.get("disk_total") or 0
    disk_free = system.get("disk_free") or 0
    if disk_total <= 0 or disk_free > disk_total:
        disk_metric = ("UNAVAILABLE", "muted")
    else:
        free_percent = int(100 * disk_free / disk_total)
        disk_metric = (
            "DISK %d%% FREE" % free_percent,
            "danger" if free_percent <= 5 else "warn" if free_percent <= 15 else "ok",
        )
    datahub = diagnostics["datahub"]
    acknowledgement_age = datahub.get("last_acknowledgement_age_seconds")
    if acknowledgement_age is None:
        acknowledgement_text = "--"
    elif acknowledgement_age < 60.0:
        acknowledgement_text = "%d S" % int(acknowledgement_age)
    elif acknowledgement_age < 3600.0:
        acknowledgement_text = "%d M" % int(acknowledgement_age / 60.0)
    elif acknowledgement_age < 86400.0:
        acknowledgement_text = "%.1f H" % (acknowledgement_age / 3600.0)
    else:
        acknowledgement_text = "%.1f D" % (acknowledgement_age / 86400.0)
    if not datahub["configured"]:
        cloud_metric = ("NOT CONFIGURED", "muted")
    elif datahub["dead_letters"]:
        cloud_metric = (
            "%d DEAD LETTERS\nLAST ACK %s"
            % (datahub["dead_letters"], acknowledgement_text),
            "danger",
        )
    elif datahub["available"] and datahub["dataset_binding_verified"]:
        cloud_metric = (
            "DATASET READY / Q %d\nLAST ACK %s"
            % (datahub["pending"], acknowledgement_text),
            "ok",
        )
    else:
        cloud_metric = (
            "DATAHUB CHECK\nLAST ACK %s" % acknowledgement_text,
            "warn",
        )
    management = diagnostics["management"]
    registry = diagnostics["registry"]
    network_metric = (
        "%s / %s"
        % (
            _safe_text(management["exposure"], 18).upper(),
            "REG OK" if registry["ready"] else "REG %s" % registry["status"].upper(),
        ),
        (
            "ok"
            if management["configured"]
            and (registry["ready"] or not registry["configured"])
            else "warn" if management["configured"] else "muted"
        ),
    )
    configured_workers = [item for item in diagnostics["workers"] if item["configured"]]
    running_workers = [item for item in configured_workers if item["running"]]
    worker_metric = (
        "%d / %d RUNNING" % (len(running_workers), len(configured_workers)),
        (
            "ok"
            if configured_workers and len(running_workers) == len(configured_workers)
            else "warn" if configured_workers else "muted"
        ),
    )
    camera_views = _mapping(view.get("cameras"))
    tool_camera = _mapping(camera_views.get("tool"))
    workspace_camera = _mapping(camera_views.get("workspace"))
    camera_detail = "T %s A%s R%s / W %s A%s R%s" % (
        "F" if tool_camera.get("healthy") is True else "!",
        _safe_text(tool_camera.get("age") or "--", 8),
        _safe_text(tool_camera.get("reconnects") or "--", 8),
        "F" if workspace_camera.get("healthy") is True else "!",
        _safe_text(workspace_camera.get("age") or "--", 8),
        _safe_text(workspace_camera.get("reconnects") or "--", 8),
    )
    ota_status = _safe_text(ota.get("status") or "UNAVAILABLE", 20).upper()
    ota_current = _safe_text(ota.get("current_version") or "--", 16)
    ota_available = _safe_text(ota.get("available_version") or "--", 16)
    gateway_state = _safe_text(view.get("state") or "UNKNOWN", 24)
    if view.get("ready") is True:
        gateway_metric = "%s\nUP %s" % (gateway_state, uptime_text)
    else:
        problem = _safe_text(view.get("problems") or "CHECKS INCOMPLETE", 28)
        if problem.startswith("Checks: "):
            problem = problem[8:]
        gateway_metric = "%s\n%s" % (gateway_state, problem)
    return {
        "gateway": (
            gateway_metric,
            _safe_text(view.get("tone") or "warn", 12),
        ),
        "cameras": (
            "%d / 2 LIVE\n%s" % (min(max(camera_count, 0), 2), camera_detail),
            "ok" if camera_count == 2 else "warn",
        ),
        "motion": (
            "%s / %s"
            % (
                _safe_text(xarm.get("summary") or "UNAVAILABLE", 20),
                _safe_text(motion.get("badge") or "NOT VERIFIED", 20),
            ),
            (
                "danger"
                if xarm.get("moving") is True
                else _safe_text(motion.get("tone") or xarm.get("tone") or "warn", 12)
            ),
        ),
        "capture": capture_metric,
        "dataset": dataset_metric,
        "ota": (
            "%s\n%s > %s" % (ota_status, ota_current, ota_available),
            _safe_text(ota.get("tone") or "muted", 12),
        ),
        "cpu": ("%s\nUP %s" % (cpu_metric[0], uptime_text), cpu_metric[1]),
        "memory": memory_metric,
        "disk": disk_metric,
        "network": network_metric,
        "workers": worker_metric,
        "cloud": cloud_metric,
    }


def _metrics_require_visible_alarm(view):
    """Inspect the fixed, bounded rendered metrics surface for danger."""

    try:
        metrics = _metrics_view(view)
    except Exception:
        return True
    if not isinstance(metrics, dict) or len(metrics) > 16:
        return True
    for metric in metrics.values():
        if not isinstance(metric, tuple) or len(metric) != 2:
            return True
        if metric[1] == "danger":
            return True
    return False


def _capture_requires_visible_stop(view):
    """Return true while an admitted physical capture must stay on screen."""

    capture = _mapping(_mapping(view).get("capture"))
    return capture.get("stop_allowed") is True


def _search_requires_visible_stop(view):
    """Return true while authoritative search state requires universal STOP."""

    return _motion_search_view(view).get("stop_allowed") is True


def _operations_require_visible_stop(view):
    """Return true while Petri or reviewed recovery owns physical motion."""

    return _operations_view(view).get("stop_allowed") is True


def _authoritative_motion_stopped(view, origin=""):
    """Accept release of the frontend STOP latch only from a safe snapshot."""

    view = _mapping(view)
    if view.get("health_authoritative") is not True:
        return False
    capture = _mapping(view.get("capture"))
    search = _mapping(view.get("motion_search"))
    motion = _mapping(view.get("motion"))
    xarm = _mapping(view.get("xarm"))
    operations_stopped = True
    if origin in ("operations", "production"):
        operations = _operations_view(view)
        operations_stopped = bool(
            operations.get("valid") is True
            and operations.get("stop_allowed") is False
            and _mapping(operations.get("petri")).get("state")
            in ("ready", "completed", "cancelled", "error", "unavailable")
            and _mapping(operations.get("recovery")).get("state")
            in ("idle", "completed", "error", "unavailable")
        )
    return (
        (
            (
                capture.get("configured") is True
                and capture.get("state")
                in ("idle", "completed", "cancelled", "failed", "interrupted")
                and capture.get("active") is False
                and capture.get("stop_allowed") is False
            )
            or (
                capture.get("configured") is False
                and search.get("state") in ("ready", "locked", "unavailable")
            )
        )
        and motion.get("verified_locked") is True
        and xarm.get("moving") is False
        and operations_stopped
    )


def _latched_stop_capture(current, previous):
    """Return a bounded capture view that keeps immediate STOP actionable."""

    current = _mapping(current)
    previous = _mapping(previous)
    source = current if current.get("configured") is True else previous
    result = dict(source or _capture_view({}))
    fault_locked = source.get("state") == "fault_locked"
    result.update(
        {
            "configured": True,
            # While admission is uncertain, treat the physical operation as
            # active.  This is display-local state and is cleared only from a
            # validated backend terminal/locked snapshot.
            "active": True,
            "action_allowed": False,
            "stop_allowed": True,
            "state": (
                "fault_locked"
                if fault_locked
                else ("stopping" if source.get("state") == "stopping" else "running")
            ),
            "tone": "danger",
            "headline": (
                "SICHERHEITSFEHLER - BEWEGUNG GESPERRT"
                if fault_locked
                else "MOTION-STATUS WIRD VERIFIZIERT"
            ),
            "detail": (
                "NOT-AUS BETAETIGEN UND ANLAGE PRUEFEN; SOFTWARE-STOP BLEIBT AKTIV"
                if fault_locked
                else "Software-STOP bleibt aktiv bis der Backend-Lock bestaetigt ist"
            ),
            "button": "SOFTWARE STOP WIEDERHOLEN" if fault_locked else "SOFORT STOPPEN",
        }
    )
    return result


def _reconcile_motion_stop_latch(view, previous_capture, latched, origin=""):
    """Reconcile a display-local STOP latch with one health snapshot.

    Only a shape-validated, authoritative, terminal and stationary snapshot
    can clear the latch.  Every other input retains a fully actionable STOP
    presentation, including transport outages and fault-locked states.
    """

    view = _mapping(view)
    if not latched:
        return view, False
    if _authoritative_motion_stopped(view, origin=origin):
        return view, False
    result = dict(view)
    result["capture"] = _latched_stop_capture(
        view.get("capture"),
        previous_capture,
    )
    return result, True


def _create_sdl_touch_input(lv):
    """Create the official SDL mouse/touch indev or fail visibly."""

    create_pointer = getattr(lv, "sdl_mouse_create", None)
    if not callable(create_pointer):
        raise RuntimeError("official LVGL SDL touch input is unavailable")
    touch_input = create_pointer()
    if touch_input is None:
        raise RuntimeError("official LVGL SDL touch input failed")
    return touch_input


def _lvgl_version_text(lv):
    """Return a bounded, non-identifying LVGL version diagnostic."""

    parts = []
    for name in ("major", "minor", "patch"):
        getter = getattr(lv, "version_%s" % name, None)
        value = None
        if callable(getter):
            try:
                value = getter()
            except Exception:
                value = None
        if value is None:
            value = getattr(lv, "VERSION_%s" % name.upper(), None)
        if isinstance(value, bool) or not isinstance(value, int):
            return "unknown"
        if value < 0 or value > 999:
            return "unknown"
        parts.append(str(value))
    return ".".join(parts)


class GatewayStatusFrontend:
    """Responsive LVGL v9/SDL view for the local gateway health endpoint."""

    BG = 0x071116
    PANEL = 0x0D1C24
    CARD = 0x10242E
    BORDER = 0x23404C
    TEXT = 0xF2F7F8
    MUTED = 0x94ADB7
    DIM = 0x66808A
    OK = 0x39D69F
    WARN = 0xF5B642
    DANGER = 0xFF6B6B
    ACCENT = 0x63D4FF
    INK = 0x071116

    def __init__(self, lv, config):
        self.lv = lv
        self.config = config
        self._set_dimensions(config["width"], config["height"])
        self.font_small = getattr(lv, "font_montserrat_14", None)
        self.font_body = getattr(lv, "font_montserrat_16", self.font_small)
        self.font_title = getattr(lv, "font_montserrat_24", self.font_body)
        self._update_request_pending = False
        self._capture_request_pending = False
        self._motion_search_request_pending = False
        self._safety_configuration_request_pending = False
        self._operations_request_pending = False
        self._workspace_teach_request_pending = False
        self._tenant_auth_request_pending = False
        self._hand_training_request_pending = False
        self._tenant_auth_local_status = ""
        self._tenant_auth_waiting = {}
        self._software_stop_request_pending = False
        self._capture_start_challenge = ""
        self._motion_search_challenge = ""
        self._safety_configuration_challenge = ""
        self._safety_configuration_digest = ""
        self._petri_start_challenge = ""
        self._recovery_start_challenge = ""
        self._manual_review_challenge = ""
        self._manual_review_candidate = {}
        self._manual_review_preview_ready = False
        self._manual_review_preview_bytes = None
        self._manual_review_preview_descriptor = None
        self._manual_review_preview_retired = []
        self._workspace_teach_finalize_challenge = ""
        self._workspace_teach_finalize_digest = ""
        self._workspace_teach_finalize_session_id = ""
        self._workspace_teach_finalize_started_ms = 0
        self._workspace_teach_notice_acknowledged = False
        self._workspace_teach_waiting = {}
        self._last_safety_configuration_view = _safety_configuration_view({})
        self._safety_configuration_local_pending = False
        self._last_motion_search_view = _motion_search_view({})
        self._last_digital_twin_view = _digital_twin_view({})
        self._last_workspace_teach_view = _workspace_teach_view({})
        self._last_tenant_auth_view = _tenant_auth_view({})
        self._twin_projection = "isometric"
        self._last_operations_view = _operations_view({})
        # This frontend-owned latch closes the gap between admission of a
        # physical capture run and the next health poll.  Once the backend
        # accepts the second confirmation, STOP must remain visible even when
        # health transport or schema validation temporarily fails.  Only a
        # later authoritative, healthy and locked snapshot may clear it.
        self._motion_stop_latched = False
        self._motion_stop_origin = ""
        self._last_ota_view = _ota_view({})
        self._last_capture_view = _capture_view({})
        self._last_view = self._offline_view()
        self._active_view = "home"
        self._robot_metrics_page_index = 0
        self._layout_pending = False
        self._screensaver_active = False
        self._screensaver_wake_guard = False
        self._screensaver_capability_enabled = False
        # Fail open to visible status until the first authoritative health
        # view has reduced the fixed metrics alarm surface.
        self._screensaver_metrics_alarm = True
        self._screensaver_visibility_blocked_last = True
        self._screensaver_last_visibility_reasons = ("health_unavailable",)
        self._screensaver_reveal_count = 0
        self._screensaver_last_reveal_reason = ""
        self._screensaver_last_reveal_local_ms = None
        self._screensaver_last_reveal_poll_ms = None
        self._screensaver_max_reveal_poll_ms = None
        self._pending_health_poll_started_ms = None
        self._health_poll_epoch = 0
        self._last_interaction_ms = _monotonic_ms()
        self._last_input_activity_ms = None
        self._input_activity_event_count = 0
        self._input_activity_reconnect_count = 0
        self._input_activity_state = "initializing"
        self._input_activity_reason = "initializing"
        self._input_activity_event_path = "none"
        self._input_activity_pressed_supported = False
        self._input_activity_released_supported = False
        self._input_activity_monitor_supported = False
        self._input_activity_connected = False
        self._input_activity_ever_connected = False
        self._input_activity_pressed = False
        self._input_uncertain_contact = False
        self._input_uncertain_press_seen = False
        self._input_uncertain_release_seen = False
        self._input_activity_state_getter = None
        self._input_activity_monitor_initialized = False
        self._input_activity_last_report = None
        self._input_driver_kind = "sdl_mouse"
        self._lvgl_version = _lvgl_version_text(lv)
        self._layout_generation = 0
        self._layout_input_ready = False
        self._screensaver_foreground_generation = -1
        self._guarded_click_callbacks = []
        self._retired_layouts = []
        self._challenge_validity = {}
        self._preview_descriptors = {"tool": None, "workspace": None}
        self._preview_bytes = {"tool": None, "workspace": None}
        self._preview_retired = {"tool": [], "workspace": []}
        self._action_epoch = 0
        # MicroPython and LVGL stay on this one thread.  The companion CPython
        # broker owns two independent subprocess lanes; the UI publishes only
        # immutable descriptors into its bounded private mailbox.
        self._transport = _BrokerMailbox()

        self.display = lv.sdl_window_create(config["width"], config["height"])
        if hasattr(self.display, "set_default"):
            self.display.set_default()
        # The official SDL pointer input device covers both a mouse and a
        # compositor-mapped touchscreen.  Keep the indev alive for the whole
        # frontend lifetime; a display without touch must fail at startup
        # instead of presenting controls that cannot be operated.
        self.touch_input = _create_sdl_touch_input(lv)
        self._input_activity_callback = self._touch_activity
        self._initialize_input_activity_monitor()
        if hasattr(lv, "sdl_window_set_title"):
            lv.sdl_window_set_title(self.display, "LabCobot Runtime")
        if hasattr(lv, "sdl_window_set_zoom"):
            lv.sdl_window_set_zoom(self.display, config["zoom"])
        if hasattr(lv, "sdl_window_set_resizeable"):
            lv.sdl_window_set_resizeable(self.display, False)

        self._build_screen()
        self._resolution_change_callback = self._queue_resolution_change
        resolution_event = getattr(self.lv.EVENT, "RESOLUTION_CHANGED", None)
        add_display_event = getattr(self.display, "add_event_cb", None)
        if resolution_event is not None and callable(add_display_event):
            add_display_event(
                self._resolution_change_callback,
                resolution_event,
                None,
            )
        # The pinned SDL driver sends RESOLUTION_CHANGED when labwc forces the
        # window fullscreen.  Poll as a compatibility fallback for bindings
        # that expose the resolution getters but not display event callbacks.
        self._resolution_timer_callback = self._check_resolution
        self.resolution_timer = lv.timer_create(
            self._resolution_timer_callback,
            100,
            None,
        )
        self._timer_callback = self.refresh
        self.timer = lv.timer_create(self._timer_callback, config["poll_ms"], None)
        self._preview_timer_callback = self.refresh_preview
        self.preview_timer = lv.timer_create(
            self._preview_timer_callback,
            1000,
            None,
        )
        self._completion_timer_callback = self._drain_async_results
        self.completion_timer = lv.timer_create(
            self._completion_timer_callback,
            COMPLETION_CHECK_MS,
            None,
        )
        self._screensaver_timer_callback = self._check_screensaver
        self.screensaver_timer = lv.timer_create(
            self._screensaver_timer_callback,
            SCREENSAVER_CHECK_MS,
            None,
        )
        self.refresh()

    def _input_event_registrar(self):
        method = getattr(self.touch_input, "add_event_cb", None)
        if callable(method):
            return method, "indev_method"
        indev_type = getattr(self.lv, "indev", None)
        method = getattr(indev_type, "add_event_cb", None)
        if callable(method):
            return (
                lambda callback, code, data: method(
                    self.touch_input,
                    callback,
                    code,
                    data,
                )
            ), "indev_type"
        method = getattr(self.lv, "indev_add_event_cb", None)
        if callable(method):
            return (
                lambda callback, code, data: method(
                    self.touch_input,
                    callback,
                    code,
                    data,
                )
            ), "indev_function"
        return None, "none"

    def _input_state_reader(self):
        method = getattr(self.touch_input, "get_state", None)
        if callable(method):
            return method
        indev_type = getattr(self.lv, "indev", None)
        method = getattr(indev_type, "get_state", None)
        if callable(method):
            return lambda: method(self.touch_input)
        method = getattr(self.lv, "indev_get_state", None)
        if callable(method):
            return lambda: method(self.touch_input)
        return None

    def _disable_input_activity(self, reason, disconnected=False, now_ms=None):
        self._screensaver_capability_enabled = False
        self._input_activity_state = "disconnected" if disconnected else "degraded"
        self._input_activity_reason = reason
        if disconnected:
            self._input_activity_connected = False
            self._mark_uncertain_input_contact()
        if getattr(self, "_screensaver_active", False):
            self._hide_screensaver(now_ms=now_ms, guard_wake=True)
        elif hasattr(self, "screen"):
            self._record_interaction(now_ms=now_ms)
        self._report_input_activity_diagnostic()
        return False

    def _initialize_input_activity_monitor(self):
        """Bind the documented v9 indev events or disable blanking visibly."""

        event_type = getattr(self.lv, "EVENT", None)
        pressed_event = getattr(event_type, "PRESSED", None)
        released_event = getattr(event_type, "RELEASED", None)
        if pressed_event is None:
            return self._disable_input_activity("pressed_event_missing")
        if released_event is None:
            return self._disable_input_activity("released_event_missing")
        try:
            duplicate_codes = pressed_event == released_event
        except Exception:
            duplicate_codes = True
        if duplicate_codes:
            return self._disable_input_activity("event_codes_invalid")

        registrar, event_path = self._input_event_registrar()
        self._input_activity_event_path = event_path
        if not callable(registrar):
            return self._disable_input_activity("event_api_missing")
        try:
            result = registrar(self._input_activity_callback, pressed_event, None)
            if result is False:
                return self._disable_input_activity("pressed_registration_rejected")
            self._input_activity_pressed_supported = True
        except Exception:
            return self._disable_input_activity("pressed_registration_rejected")
        try:
            result = registrar(self._input_activity_callback, released_event, None)
            if result is False:
                return self._disable_input_activity("released_registration_rejected")
            self._input_activity_released_supported = True
        except Exception:
            return self._disable_input_activity("released_registration_rejected")

        state_reader = self._input_state_reader()
        if not callable(state_reader):
            return self._disable_input_activity("state_api_missing")
        indev_state = getattr(self.lv, "INDEV_STATE", None)
        self._input_activity_pressed_state = getattr(indev_state, "PRESSED", None)
        self._input_activity_released_state = getattr(indev_state, "RELEASED", None)
        if (
            self._input_activity_pressed_state is None
            or self._input_activity_released_state is None
        ):
            return self._disable_input_activity("state_values_missing")
        try:
            duplicate_states = (
                self._input_activity_pressed_state
                == self._input_activity_released_state
            )
        except Exception:
            duplicate_states = True
        if duplicate_states:
            return self._disable_input_activity("state_values_invalid")
        self._input_activity_state_getter = state_reader
        self._input_activity_monitor_supported = True
        self._input_activity_monitor_initialized = True
        return self._poll_input_activity(initial=True)

    def _read_input_pressed(self):
        state = self._input_activity_state_getter()
        if state == self._input_activity_pressed_state:
            return True
        if state == self._input_activity_released_state:
            return False
        raise ValueError("input state is outside the closed vocabulary")

    def _mark_uncertain_input_contact(self, pressed=None):
        self._input_uncertain_contact = True
        self._input_uncertain_press_seen = pressed is True
        self._input_uncertain_release_seen = pressed is False
        self._screensaver_wake_guard = True

    def _clear_uncertain_input_contact(self):
        self._input_uncertain_contact = False
        self._input_uncertain_press_seen = False
        self._input_uncertain_release_seen = False

    def _poll_input_activity(self, now_ms=None, initial=False):
        if not getattr(self, "_input_activity_monitor_initialized", False):
            return False
        now = _monotonic_ms() if now_ms is None else int(now_ms)
        try:
            pressed = self._read_input_pressed()
        except Exception:
            return self._disable_input_activity(
                "state_read_failed",
                disconnected=True,
                now_ms=now,
            )

        was_connected = bool(getattr(self, "_input_activity_connected", False))
        ever_connected = bool(getattr(self, "_input_activity_ever_connected", False))
        reconnect = ever_connected and not was_connected
        self._input_activity_connected = True
        self._input_activity_ever_connected = True
        self._input_activity_pressed = pressed
        if reconnect:
            self._input_activity_reconnect_count = min(
                int(getattr(self, "_input_activity_reconnect_count", 0)) + 1,
                MAX_INPUT_ACTIVITY_COUNT,
            )
            self._mark_uncertain_input_contact(pressed=pressed)
            if getattr(self, "_screensaver_active", False):
                self._hide_screensaver(now_ms=now, guard_wake=True)
            else:
                self._record_interaction(now_ms=now)
        elif initial and pressed:
            # A process restart may begin during an already-held contact.
            # Its release/click is not valid action provenance.
            self._mark_uncertain_input_contact(pressed=True)
        elif getattr(self, "_input_uncertain_contact", False) and not pressed:
            self._input_uncertain_release_seen = True

        self._screensaver_capability_enabled = bool(
            self._input_activity_pressed_supported
            and self._input_activity_released_supported
            and self._input_activity_monitor_supported
        )
        self._input_activity_state = "supported"
        self._input_activity_reason = "ok"
        self._report_input_activity_diagnostic()
        return True

    def input_activity_diagnostics(self, now_ms=None):
        now = _monotonic_ms() if now_ms is None else int(now_ms)
        last_activity = getattr(self, "_last_input_activity_ms", None)
        age_ms = None
        if isinstance(last_activity, int) and not isinstance(last_activity, bool):
            age_ms = min(
                _elapsed_ms(last_activity, now),
                MAX_INPUT_ACTIVITY_AGE_MS,
            )
        return {
            "schema_version": INPUT_ACTIVITY_DIAGNOSTIC_SCHEMA_VERSION,
            "state": getattr(self, "_input_activity_state", "degraded"),
            "reason": getattr(self, "_input_activity_reason", "not_initialized"),
            "policy": "disable_screensaver",
            "lvgl_version": getattr(self, "_lvgl_version", "unknown"),
            "driver_kind": getattr(self, "_input_driver_kind", "unknown"),
            "event_path": getattr(self, "_input_activity_event_path", "none"),
            "pressed_supported": bool(
                getattr(self, "_input_activity_pressed_supported", False)
            ),
            "released_supported": bool(
                getattr(self, "_input_activity_released_supported", False)
            ),
            "connection_monitor_supported": bool(
                getattr(self, "_input_activity_monitor_supported", False)
            ),
            "connected": bool(getattr(self, "_input_activity_connected", False)),
            "screensaver_enabled": bool(
                getattr(self, "_screensaver_capability_enabled", False)
            ),
            "uncertain_contact": bool(getattr(self, "_input_uncertain_contact", False)),
            "reconnect_count": min(
                max(int(getattr(self, "_input_activity_reconnect_count", 0)), 0),
                MAX_INPUT_ACTIVITY_COUNT,
            ),
            "event_count": min(
                max(int(getattr(self, "_input_activity_event_count", 0)), 0),
                MAX_INPUT_ACTIVITY_COUNT,
            ),
            "last_input_age_ms": age_ms,
        }

    def _report_input_activity_diagnostic(self):
        diagnostic = self.input_activity_diagnostics()
        signature = (
            diagnostic["state"],
            diagnostic["reason"],
            diagnostic["event_path"],
            diagnostic["connected"],
            diagnostic["screensaver_enabled"],
            diagnostic["reconnect_count"],
        )
        if signature == getattr(self, "_input_activity_last_report", None):
            return False
        self._input_activity_last_report = signature
        print(
            "LABCOBOT_LVGL_INPUT state=%s reason=%s lvgl=%s driver=%s "
            "path=%s pressed=%d released=%d monitor=%d connected=%d "
            "screensaver=%d reconnects=%d"
            % (
                diagnostic["state"],
                diagnostic["reason"],
                diagnostic["lvgl_version"],
                diagnostic["driver_kind"],
                diagnostic["event_path"],
                int(diagnostic["pressed_supported"]),
                int(diagnostic["released_supported"]),
                int(diagnostic["connection_monitor_supported"]),
                int(diagnostic["connected"]),
                int(diagnostic["screensaver_enabled"]),
                diagnostic["reconnect_count"],
            )
        )
        return True

    def _footer_input_status(self, text):
        diagnostic = self.input_activity_diagnostics()
        if diagnostic["state"] == "supported":
            suffix = " / TOUCH OK"
        elif diagnostic["state"] == "disconnected":
            suffix = " / TOUCH OFFLINE / SAVER OFF"
        else:
            suffix = " / TOUCH DEGRADED / SAVER OFF"
        return _safe_text(_safe_text(text, 72) + suffix, 104)

    def _submit_background(self, key, request, apply, replace=False):
        """Publish one immutable request without running transport in LVGL."""

        transport = getattr(self, "_transport", None)
        if transport is None:
            # Reducer-only/headless tests construct this class with ``__new__``
            # and can inject a complete response mapping.  Production always
            # has a display and must never fall back to executing a request.
            if hasattr(self, "display"):
                raise RuntimeError("LVGL transport mailbox is unavailable")
            if _valid_transport_request_spec(request, key):
                apply(None, RuntimeError("transport mailbox is unavailable"))
            else:
                apply(request, None)
            return True
        return transport.submit(key, request, apply, replace=replace)

    def _submit_general(self, key, request, apply, replace=False):
        if key not in _GENERAL_WORK_KEYS:
            raise ValueError("general transport key is not allowlisted")
        return self._submit_background(key, request, apply, replace=replace)

    def _submit_stop(self, request, apply):
        return self._submit_background("software-stop", request, apply, replace=False)

    def _drain_async_results(self, _timer=None):
        # Called only by an LVGL timer.  The broker never receives callbacks
        # and cannot touch LVGL or frontend state.
        transport = getattr(self, "_transport", None)
        if transport is not None:
            transport.drain()

    def _begin_action(self):
        # Health fetched before an operator action must not overwrite its
        # optimistic safety latch when that old response arrives later.
        self._action_epoch = int(getattr(self, "_action_epoch", 0)) + 1
        return self._action_epoch

    def _remember_challenge(self, attribute, token, expires_in_seconds, binding):
        """Bind one server challenge to a local action epoch and expiry."""

        if attribute not in _REBUILD_CHALLENGE_FIELDS:
            return False
        if not _lower_hex_exact(token, 32):
            return False
        if (
            isinstance(expires_in_seconds, bool)
            or not isinstance(expires_in_seconds, int)
            or not 1 <= expires_in_seconds <= 30
            or not isinstance(binding, tuple)
            or not 1 <= len(binding) <= 4
        ):
            return False
        record = {
            "token": token,
            "issued_ms": _monotonic_ms(),
            "ttl_ms": expires_in_seconds * 1000,
            "binding": binding,
        }
        validity = getattr(self, "_challenge_validity", None)
        if not isinstance(validity, dict):
            validity = {}
            self._challenge_validity = validity
        validity[attribute] = record
        setattr(self, attribute, token)
        return True

    def _expected_challenge_binding(self, attribute):
        epoch = int(getattr(self, "_action_epoch", 0))
        if attribute == "_capture_start_challenge":
            capture = _mapping(getattr(self, "_last_capture_view", {}))
            if capture.get("state") != "confirming":
                return None
            return ("capture", epoch, capture.get("run_id") or "--")
        if attribute == "_motion_search_challenge":
            search = _mapping(getattr(self, "_last_motion_search_view", {}))
            if search.get("request_result") != "confirm":
                return None
            return ("motion-search", epoch)
        if attribute == "_safety_configuration_challenge":
            digest = getattr(self, "_safety_configuration_digest", "")
            if not _lower_hex_exact(digest, 64):
                return None
            return ("safety-configure", epoch, digest)
        if attribute in ("_petri_start_challenge", "_recovery_start_challenge"):
            operation = "petri" if attribute == "_petri_start_challenge" else "recovery"
            operations = _mapping(getattr(self, "_last_operations_view", {}))
            current = _mapping(operations.get(operation))
            if current.get("state") != "confirming":
                return None
            return (operation, epoch, self._operator_ui_context(operations))
        if attribute == "_manual_review_challenge":
            candidate = _mapping(getattr(self, "_manual_review_candidate", {}))
            if not getattr(
                self, "_manual_review_preview_ready", False
            ) or not _valid_manual_review_candidate(candidate):
                return None
            return ("manual-review", epoch, candidate.get("observation_id"))
        return None

    @staticmethod
    def _operator_ui_context(operations):
        """Bind a local challenge to the displayed recipe and safety context."""

        operations = _mapping(operations)
        recipe = _mapping(operations.get("recipe"))
        preflight = _mapping(operations.get("preflight"))
        petri = _mapping(operations.get("petri"))
        recovery = _mapping(operations.get("recovery"))
        blockers = preflight.get("blockers")
        if not isinstance(blockers, tuple):
            blockers = ()
        return (
            recipe.get("recipe_id"),
            recipe.get("recipe_version"),
            recipe.get("process_profile_sha256"),
            blockers,
            preflight.get("motion_permit_ready") is True,
            petri.get("run_id"),
            petri.get("process_state"),
            petri.get("recovery_required") is True,
            recovery.get("state"),
        )

    def _challenge_for_rebuild(self, attribute, now_ms):
        token = getattr(self, attribute, "")
        if not _lower_hex_exact(token, 32):
            return "", None
        validity = _mapping(getattr(self, "_challenge_validity", {}))
        record = validity.get(attribute)
        if not isinstance(record, dict) or set(record) != {
            "token",
            "issued_ms",
            "ttl_ms",
            "binding",
        }:
            return "", None
        issued = record.get("issued_ms")
        ttl = record.get("ttl_ms")
        binding = record.get("binding")
        if (
            record.get("token") != token
            or isinstance(issued, bool)
            or not isinstance(issued, int)
            or isinstance(ttl, bool)
            or not isinstance(ttl, int)
            or not 1000 <= ttl <= 30000
            or not isinstance(binding, tuple)
            or binding != self._expected_challenge_binding(attribute)
        ):
            return "", None
        elapsed = _elapsed_ms(issued, now_ms)
        if elapsed < 0 or elapsed >= ttl:
            return "", None
        return token, {
            "token": token,
            "issued_ms": issued,
            "ttl_ms": ttl,
            "binding": binding,
        }

    def _broker_rebuild_identity(self):
        transport = getattr(self, "_transport", None)
        snapshot = getattr(transport, "rebuild_identity", None)
        if not callable(snapshot):
            return None
        try:
            return snapshot()
        except Exception:
            return None

    @staticmethod
    def _bounded_preview_bytes(value):
        if isinstance(value, bytes) and 4 <= len(value) <= MAX_SNAPSHOT_BYTES:
            return value
        return None

    def _snapshot_rebuild_state(self, now_ms=None):
        """Capture only explicitly allowlisted state for widget reconstruction."""

        now = _monotonic_ms() if now_ms is None else int(now_ms)
        active_view = getattr(self, "_active_view", "home")
        if active_view not in _REBUILD_ACTIVE_VIEWS:
            active_view = "home"
        action_epoch = getattr(self, "_action_epoch", 0)
        if (
            isinstance(action_epoch, bool)
            or not isinstance(action_epoch, int)
            or not 0 <= action_epoch <= MAX_TRANSPORT_GENERATION
        ):
            action_epoch = 0

        challenges = {}
        challenge_validity = {}
        for attribute in _REBUILD_CHALLENGE_FIELDS:
            token, record = self._challenge_for_rebuild(attribute, now)
            challenges[attribute] = token
            if record is not None:
                challenge_validity[attribute] = record

        manual_challenge_valid = bool(challenges["_manual_review_challenge"])
        candidate = _mapping(getattr(self, "_manual_review_candidate", {}))
        if not manual_challenge_valid or not _valid_manual_review_candidate(candidate):
            candidate = {}
        else:
            candidate = dict(candidate)
        manual_bytes = self._bounded_preview_bytes(
            getattr(self, "_manual_review_preview_bytes", None)
        )
        manual_ready = bool(
            manual_challenge_valid
            and candidate
            and manual_bytes is not None
            and getattr(self, "_manual_review_preview_ready", False)
        )
        if not manual_ready:
            candidate = {}

        workspace_teach = _mapping(getattr(self, "_last_workspace_teach_view", {}))
        workspace_challenge_current = bool(
            self._workspace_teach_confirmation_current(workspace_teach, now_ms=now)
        )
        workspace_waiting = _mapping(getattr(self, "_workspace_teach_waiting", {}))
        if len(workspace_waiting) > 4:
            workspace_waiting = {}
        else:
            workspace_waiting = dict(workspace_waiting)
        tenant_waiting = _mapping(getattr(self, "_tenant_auth_waiting", {}))
        if len(tenant_waiting) > 4:
            tenant_waiting = {}
        else:
            tenant_waiting = dict(tenant_waiting)

        preview_bytes = _mapping(getattr(self, "_preview_bytes", {}))
        preview_descriptors = _mapping(getattr(self, "_preview_descriptors", {}))
        preview_retired = _mapping(getattr(self, "_preview_retired", {}))
        previews = {}
        for role in ("tool", "workspace"):
            retired = preview_retired.get(role)
            if not isinstance(retired, list):
                retired = []
            previews[role] = {
                "bytes": self._bounded_preview_bytes(preview_bytes.get(role)),
                "descriptor": preview_descriptors.get(role),
                "retired": list(retired[-2:]),
            }

        views = {}
        for attribute in _REBUILD_VIEW_FIELDS:
            value = getattr(self, attribute, {})
            views[attribute] = dict(value) if isinstance(value, dict) else {}

        tenant_inputs = {"tenant_url": "", "username": ""}
        if hasattr(self, "tenant_auth_tenant_input"):
            tenant_inputs["tenant_url"] = self._tenant_input_text(
                self.tenant_auth_tenant_input,
                512,
            )
            tenant_inputs["username"] = self._tenant_input_text(
                getattr(self, "tenant_auth_username_input", None),
                254,
            )

        latched = bool(getattr(self, "_motion_stop_latched", False))
        origin = getattr(self, "_motion_stop_origin", "")
        if origin not in ("capture", "search", "operations", "production"):
            origin = "capture" if latched else ""
        return {
            "schema_version": REBUILD_STATE_SCHEMA_VERSION,
            "captured_ms": now,
            "action_epoch": action_epoch,
            "broker_identity": self._broker_rebuild_identity(),
            "active_view": active_view,
            "robot_metrics_page_index": max(
                0,
                min(int(getattr(self, "_robot_metrics_page_index", 0)), 3),
            ),
            "twin_projection": (
                getattr(self, "_twin_projection", "isometric")
                if getattr(self, "_twin_projection", "isometric")
                in ("isometric", "top", "front")
                else "isometric"
            ),
            "screensaver": {
                "active": bool(getattr(self, "_screensaver_active", False)),
                "wake_guard": bool(getattr(self, "_screensaver_wake_guard", False)),
                "last_interaction_ms": int(getattr(self, "_last_interaction_ms", now)),
                "input_pressed": bool(getattr(self, "_input_activity_pressed", False)),
                "uncertain_contact": bool(
                    getattr(self, "_input_uncertain_contact", False)
                ),
                "uncertain_press_seen": bool(
                    getattr(self, "_input_uncertain_press_seen", False)
                ),
                "uncertain_release_seen": bool(
                    getattr(self, "_input_uncertain_release_seen", False)
                ),
            },
            "stop": {"latched": latched, "origin": origin},
            "pending": {
                field: bool(getattr(self, field, False))
                for field in _REBUILD_PENDING_FIELDS
            },
            "challenges": challenges,
            "challenge_validity": challenge_validity,
            "safety_digest": (
                getattr(self, "_safety_configuration_digest", "")
                if challenges["_safety_configuration_challenge"]
                else ""
            ),
            "manual_review": {
                "candidate": candidate,
                "preview_ready": manual_ready,
                "preview_bytes": manual_bytes,
                "preview_descriptor": getattr(
                    self, "_manual_review_preview_descriptor", None
                ),
                "preview_retired": list(
                    getattr(self, "_manual_review_preview_retired", [])[-2:]
                ),
            },
            "workspace_teach": {
                "challenge": (
                    getattr(self, "_workspace_teach_finalize_challenge", "")
                    if workspace_challenge_current
                    else ""
                ),
                "digest": (
                    getattr(self, "_workspace_teach_finalize_digest", "")
                    if workspace_challenge_current
                    else ""
                ),
                "session_id": (
                    getattr(self, "_workspace_teach_finalize_session_id", "")
                    if workspace_challenge_current
                    else ""
                ),
                "started_ms": (
                    int(getattr(self, "_workspace_teach_finalize_started_ms", 0))
                    if workspace_challenge_current
                    else 0
                ),
                "notice_acknowledged": bool(
                    getattr(self, "_workspace_teach_notice_acknowledged", False)
                ),
                "waiting": workspace_waiting,
            },
            "tenant_auth": {
                "local_status": _safe_text(
                    getattr(self, "_tenant_auth_local_status", ""), 64
                ),
                "waiting": tenant_waiting,
                "inputs": tenant_inputs,
            },
            "views": views,
            "previews": previews,
        }

    def _restore_rebuild_state(self, snapshot):
        if (
            not isinstance(snapshot, dict)
            or snapshot.get("schema_version") != REBUILD_STATE_SCHEMA_VERSION
        ):
            return False
        broker_matches = bool(
            snapshot.get("broker_identity") == self._broker_rebuild_identity()
        )
        self._action_epoch = int(snapshot.get("action_epoch") or 0)
        for field in _REBUILD_PENDING_FIELDS:
            setattr(
                self,
                field,
                (
                    bool(_mapping(snapshot.get("pending")).get(field))
                    if broker_matches
                    else False
                ),
            )

        challenges = _mapping(snapshot.get("challenges"))
        for field in _REBUILD_CHALLENGE_FIELDS:
            setattr(
                self,
                field,
                challenges.get(field, "") if broker_matches else "",
            )
        self._challenge_validity = (
            dict(_mapping(snapshot.get("challenge_validity"))) if broker_matches else {}
        )
        self._safety_configuration_digest = (
            snapshot.get("safety_digest", "") if broker_matches else ""
        )

        views = _mapping(snapshot.get("views"))
        for field in _REBUILD_VIEW_FIELDS:
            value = views.get(field)
            if isinstance(value, dict):
                setattr(self, field, dict(value))

        stop = _mapping(snapshot.get("stop"))
        self._motion_stop_latched = bool(stop.get("latched"))
        self._motion_stop_origin = stop.get("origin", "")
        self._active_view = snapshot.get("active_view", "home")
        self._robot_metrics_page_index = int(
            snapshot.get("robot_metrics_page_index") or 0
        )
        self._twin_projection = snapshot.get("twin_projection", "isometric")

        screensaver = _mapping(snapshot.get("screensaver"))
        self._screensaver_active = bool(screensaver.get("active"))
        self._screensaver_wake_guard = bool(screensaver.get("wake_guard"))
        self._last_interaction_ms = int(
            screensaver.get("last_interaction_ms") or snapshot.get("captured_ms") or 0
        )
        self._input_activity_pressed = bool(screensaver.get("input_pressed"))
        self._input_uncertain_contact = bool(screensaver.get("uncertain_contact"))
        self._input_uncertain_press_seen = bool(screensaver.get("uncertain_press_seen"))
        self._input_uncertain_release_seen = bool(
            screensaver.get("uncertain_release_seen")
        )
        overlay = getattr(self, "screensaver_overlay", None)
        if overlay is not None:
            try:
                if self._screensaver_active:
                    overlay.remove_flag(self.lv.obj.FLAG.HIDDEN)
                else:
                    overlay.add_flag(self.lv.obj.FLAG.HIDDEN)
            except Exception:
                self._layout_input_ready = False

        manual = _mapping(snapshot.get("manual_review"))
        self._manual_review_candidate = dict(_mapping(manual.get("candidate")))
        self._manual_review_preview_ready = bool(manual.get("preview_ready"))
        self._manual_review_preview_bytes = manual.get("preview_bytes")
        self._manual_review_preview_descriptor = manual.get("preview_descriptor")
        self._manual_review_preview_retired = list(manual.get("preview_retired") or ())[
            -2:
        ]

        teach = _mapping(snapshot.get("workspace_teach"))
        self._workspace_teach_finalize_challenge = (
            teach.get("challenge", "") if broker_matches else ""
        )
        self._workspace_teach_finalize_digest = (
            teach.get("digest", "") if broker_matches else ""
        )
        self._workspace_teach_finalize_session_id = (
            teach.get("session_id", "") if broker_matches else ""
        )
        self._workspace_teach_finalize_started_ms = (
            int(teach.get("started_ms") or 0) if broker_matches else 0
        )
        self._workspace_teach_notice_acknowledged = bool(
            teach.get("notice_acknowledged")
        )
        self._workspace_teach_waiting = (
            dict(_mapping(teach.get("waiting"))) if broker_matches else {}
        )

        tenant = _mapping(snapshot.get("tenant_auth"))
        self._tenant_auth_local_status = tenant.get("local_status", "")
        self._tenant_auth_waiting = (
            dict(_mapping(tenant.get("waiting"))) if broker_matches else {}
        )
        inputs = _mapping(tenant.get("inputs"))
        for widget_name, input_name in (
            ("tenant_auth_tenant_input", "tenant_url"),
            ("tenant_auth_username_input", "username"),
        ):
            widget = getattr(self, widget_name, None)
            setter = getattr(widget, "set_text", None)
            if callable(setter):
                try:
                    setter(inputs.get(input_name, ""))
                except Exception:
                    pass
        self._clear_tenant_password(getattr(self, "tenant_auth_password_input", None))

        previews = _mapping(snapshot.get("previews"))
        self._preview_bytes = {}
        self._preview_descriptors = {}
        self._preview_retired = {}
        for role in ("tool", "workspace"):
            preview = _mapping(previews.get(role))
            self._preview_bytes[role] = preview.get("bytes")
            self._preview_descriptors[role] = preview.get("descriptor")
            self._preview_retired[role] = list(preview.get("retired") or ())[-2:]

        if not broker_matches:
            # A generation/epoch change is an action boundary, never evidence
            # that a pending physical request did not cross the broker.
            self._action_epoch = min(
                self._action_epoch + 1,
                MAX_TRANSPORT_GENERATION,
            )
        return broker_matches

    def _rerender_rebuild_state(self):
        self._apply_ota(getattr(self, "_last_ota_view", _ota_view({})))
        self._apply_capture(getattr(self, "_last_capture_view", _capture_view({})))
        if hasattr(self, "system_xarm_eyebrow"):
            self._apply_system(getattr(self, "_last_view", {}))
        self._apply_digital_twin(getattr(self, "_last_view", {}))
        preserved_view = dict(_mapping(getattr(self, "_last_view", {})))
        preserved_view["workspace_teach"] = getattr(
            self, "_last_workspace_teach_view", _workspace_teach_view({})
        )
        preserved_view["tenant_auth"] = getattr(
            self, "_last_tenant_auth_view", _tenant_auth_view({})
        )
        self._apply_workspace_teach(preserved_view)
        self._apply_tenant_auth(preserved_view)
        if hasattr(self, "safety_headline"):
            self._apply_safety_configuration(getattr(self, "_last_view", {}))
        if hasattr(self, "operation_cards"):
            self._apply_operations(getattr(self, "_last_operations_view", {}))
        if hasattr(self, "production_cards"):
            self._apply_production(
                getattr(self, "_last_view", {}),
                getattr(self, "_last_operations_view", {}),
            )
        if hasattr(self, "manual_review_candidate_label"):
            self._apply_manual_review_page()
        apply_stop = getattr(self, "_apply_software_stop_nav", None)
        if callable(apply_stop) and (
            hasattr(self, "software_stop_nav")
            or "_apply_software_stop_nav" in getattr(self, "__dict__", {})
        ):
            apply_stop(getattr(self, "_last_capture_view", _capture_view({})))
        for role in ("tool", "workspace"):
            jpeg = _mapping(getattr(self, "_preview_bytes", {})).get(role)
            if jpeg is not None and role in getattr(self, "camera_page_widgets", {}):
                self._apply_preview_jpeg(role, jpeg)
        activate = getattr(self, "_activate_view", None)
        if callable(activate) and (
            hasattr(self, "_overlays")
            or "_activate_view" in getattr(self, "__dict__", {})
        ):
            target = getattr(self, "_active_view", "home")
            if getattr(self, "_motion_stop_latched", False):
                origin = getattr(self, "_motion_stop_origin", "")
                target = (
                    ("digital_twin" if target == "digital_twin" else "system")
                    if origin == "search"
                    else origin if origin in ("operations", "production") else "capture"
                )
            activate(target, invalidate=False)

    def _retire_replaced_layout(self, screen, callbacks):
        deleted = False
        delete = getattr(screen, "delete", None)
        if callable(delete):
            try:
                delete()
                deleted = True
            except Exception:
                pass
        retired = getattr(self, "_retired_layouts", None)
        if not isinstance(retired, list):
            retired = []
            self._retired_layouts = retired
        retired.append(
            {
                "screen": None if deleted else screen,
                "callbacks": tuple(callbacks),
            }
        )
        self._prune_retired_layouts()
        return deleted

    def _prune_retired_layouts(self):
        retired = getattr(self, "_retired_layouts", None)
        if not isinstance(retired, list):
            return
        failed = [item for item in retired if item.get("screen") is not None]
        deleted = [item for item in retired if item.get("screen") is None]
        available = max(0, MAX_RETIRED_LAYOUTS - len(failed))
        retired[:] = failed[:MAX_RETIRED_LAYOUTS] + (
            deleted[-available:] if available else []
        )

    def _retry_failed_layout_deletes(self):
        retired = getattr(self, "_retired_layouts", None)
        if not isinstance(retired, list):
            return True
        for item in retired:
            screen = item.get("screen")
            if screen is None:
                continue
            delete = getattr(screen, "delete", None)
            if not callable(delete):
                continue
            try:
                delete()
                item["screen"] = None
            except Exception:
                pass
        self._prune_retired_layouts()
        failed = sum(1 for item in retired if item.get("screen") is not None)
        return failed < MAX_RETIRED_LAYOUTS

    def _start_async_flow(self, key, flow, stop=False):
        """Drive at most two fixed broker requests without blocking LVGL."""

        try:
            first_request = next(flow)
        except StopIteration:
            return False
        except Exception:
            # Descriptor construction must also fail closed.  In production
            # it performs validation only, but malformed local configuration
            # must never escape an LVGL event callback or leave a busy flag
            # permanently latched.
            try:
                flow.close()
            except Exception:
                pass
            if stop:
                self._software_stop_request_pending = False
            else:
                self._cancel_async_flow(key)
            return False
        flow_epoch = int(getattr(self, "_action_epoch", 0))
        state = {"steps": 0, "closed": False}

        def close_flow(cancel=False):
            if state["closed"]:
                return
            state["closed"] = True
            try:
                flow.close()
            except Exception:
                pass
            if cancel:
                if stop:
                    self._software_stop_request_pending = False
                else:
                    self._cancel_async_flow(key)

        def submit_step(request):
            if state["closed"]:
                return False
            # Existing reducer-only tests inject response-producing builders.
            # Production builders perform validation and return a two-key
            # immutable descriptor; they do no I/O.
            if callable(request):
                try:
                    request = request()
                except Exception:
                    close_flow(cancel=True)
                    return False
            state["steps"] += 1
            if state["steps"] > (1 if stop else 2):
                close_flow(cancel=True)
                return False

            def apply(result, error):
                if not stop and flow_epoch != int(getattr(self, "_action_epoch", 0)):
                    # A newer physical action (most importantly universal STOP)
                    # invalidates this response. Never resurrect an old
                    # challenge after the newer safety boundary.
                    close_flow(cancel=True)
                    return
                if error is not None:
                    result = {
                        "http_status": 0,
                        "payload": {},
                        "transport_error": "local request unavailable",
                    }
                try:
                    next_request = flow.send(result)
                except StopIteration:
                    close_flow()
                    return
                except Exception:
                    close_flow(cancel=True)
                    return
                if state["steps"] >= (1 if stop else 2):
                    close_flow(cancel=True)
                    return
                if not submit_step(next_request):
                    close_flow(cancel=True)

            try:
                if stop:
                    submitted = self._submit_stop(request, apply)
                else:
                    submitted = self._submit_general(key, request, apply, replace=False)
            except (TypeError, ValueError):
                submitted = False
            if not submitted:
                try:
                    apply(None, RuntimeError("local transport is busy"))
                except Exception:
                    pass
            return submitted

        return submit_step(first_request)

    def _cancel_async_flow(self, key):
        if key == "motion-search":
            self._motion_search_request_pending = False
            self._motion_search_challenge = ""
        elif key == "safety-configure":
            self._safety_configuration_request_pending = False
            self._safety_configuration_challenge = ""
            self._safety_configuration_digest = ""
        elif key == "capture":
            self._capture_request_pending = False
            self._capture_start_challenge = ""
        elif key == "update":
            self._update_request_pending = False
        elif key == "operations":
            self._operations_request_pending = False
            self._petri_start_challenge = ""
            self._recovery_start_challenge = ""
            self._manual_review_challenge = ""
            self._manual_review_candidate = {}
            self._manual_review_preview_ready = False
            self._clear_manual_review_preview_source()
        elif key == "workspace-teach":
            self._workspace_teach_request_pending = False
            self._workspace_teach_waiting = {}
            self._clear_workspace_teach_finalize_challenge()
        elif key == "hand-training":
            self._hand_training_request_pending = False

    def _set_dimensions(self, width, height):
        self.width = int(width)
        self.height = int(height)
        self.scale = min(self.width / 800.0, self.height / 480.0)
        if self.scale < 0.8:
            self.scale = 0.8
        if self.scale > 2.2:
            self.scale = 2.2

    def _build_screen(self):
        lv = self.lv
        self._layout_generation = int(getattr(self, "_layout_generation", 0)) + 1
        self._layout_input_ready = False
        # MicroPython's FFI needs callback references for the active widget
        # tree only. Drop references retained from a replaced resize layout.
        self._guarded_click_callbacks = []
        self.screen = lv.obj()
        self.screen.set_style_bg_color(lv.color_hex(self.BG), 0)
        self.screen.set_style_bg_opa(lv.OPA.COVER, 0)
        self._disable_scroll(self.screen)

        margin = max(12, int(18 * self.scale))
        gap = max(8, int(10 * self.scale))
        canvas_width = min(self.width - (margin * 2), 1500)
        canvas_x = (self.width - canvas_width) // 2
        header_height = max(58, int(66 * self.scale))
        hero_height = max(78, int(88 * self.scale))
        footer_height = max(38, int(44 * self.scale))
        hero_y = header_height
        cards_y = hero_y + hero_height + gap
        cards_height = self.height - cards_y - footer_height - margin

        logo_size = max(38, int(42 * min(self.scale, 1.4)))
        self.logo = self._panel(
            self.screen,
            canvas_x,
            margin,
            logo_size,
            logo_size,
            self.OK,
            self.OK,
            10,
        )
        self.logo_label = self._label(self.logo, "LC", 0, 0, self.INK, self.font_body)
        self.logo_label.align(lv.ALIGN.CENTER, 0, 0)
        title_x = canvas_x + logo_size + max(12, int(14 * self.scale))
        self.title = self._label(
            self.screen,
            "LABCOBOT",
            title_x,
            margin - 1,
            self.TEXT,
            self.font_title,
        )
        self.subtitle = self._label(
            self.screen,
            "DUAL VISION RUNTIME  /  ROLE NOT VERIFIED",
            title_x,
            margin + max(27, int(28 * min(self.scale, 1.3))),
            self.MUTED,
            self.font_small,
        )
        pill_width = max(112, int(128 * min(self.scale, 1.4)))
        pill_height = max(34, int(36 * min(self.scale, 1.25)))
        header_badge_x = canvas_x + canvas_width - pill_width
        self.header_badge = self._panel(
            self.screen,
            header_badge_x,
            margin + 2,
            pill_width,
            pill_height,
            self.WARN,
            self.WARN,
            pill_height // 2,
        )
        self.header_badge_label = self._label(
            self.header_badge, "CONNECTING", 0, 0, self.INK, self.font_small
        )
        self.header_badge_label.align(lv.ALIGN.CENTER, 0, 0)
        home_nav_width = max(84, int(96 * min(self.scale, 1.3)))
        self.home_nav = self._panel(
            self.screen,
            header_badge_x - gap - home_nav_width,
            margin + 2,
            home_nav_width,
            pill_height,
            self.CARD,
            self.ACCENT,
            pill_height // 2,
        )
        self.home_nav_label = self._label(
            self.home_nav,
            "START",
            0,
            0,
            self.ACCENT,
            self.font_small,
        )
        self.home_nav_label.align(lv.ALIGN.CENTER, 0, 0)
        self._open_home_callback = self._show_home
        self._make_clickable(self.home_nav, self._open_home_callback)

        self.hero = self._panel(
            self.screen,
            canvas_x,
            hero_y,
            canvas_width,
            hero_height,
            self.PANEL,
            self.BORDER,
            14,
        )
        hero_pad = max(16, int(20 * min(self.scale, 1.5)))
        self.hero_rail = self._panel(
            self.hero,
            0,
            hero_pad,
            max(5, int(6 * self.scale)),
            hero_height - (hero_pad * 2),
            self.WARN,
            self.WARN,
            3,
        )
        self.hero_state = self._label(
            self.hero,
            "CONNECTING",
            hero_pad,
            max(12, int(15 * self.scale)),
            self.WARN,
            self.font_title,
        )
        self.hero_detail = self._label(
            self.hero,
            "Waiting for the local runtime",
            hero_pad,
            max(43, int(48 * min(self.scale, 1.5))),
            self.MUTED,
            self.font_body,
        )
        metric_width = max(112, int(135 * min(self.scale, 1.35)))
        metric_gap = max(8, int(10 * self.scale))
        metric_y = max(12, int(14 * self.scale))
        metric_x = canvas_width - hero_pad - (metric_width * 2) - metric_gap
        self.camera_metric = self._hero_metric(
            self.hero, metric_x, metric_y, metric_width, "CAMERAS", "0 / 2 LIVE"
        )
        self.safety_metric = self._hero_metric(
            self.hero,
            metric_x + metric_width + metric_gap,
            metric_y,
            metric_width,
            "SAFETY",
            "UNKNOWN",
        )

        card_gap_total = gap * 2
        card_width = (canvas_width - card_gap_total) // 3
        self.camera_cards = {
            "tool": self._camera_card(
                canvas_x, cards_y, card_width, cards_height, "TOOL CAMERA"
            ),
            "workspace": self._camera_card(
                canvas_x + card_width + gap,
                cards_y,
                card_width,
                cards_height,
                "WORKSPACE CAMERA",
            ),
        }
        self.motion_card = self._motion_card(
            canvas_x + ((card_width + gap) * 2),
            cards_y,
            canvas_width - ((card_width + gap) * 2),
            cards_height,
        )

        footer_y = self.height - footer_height
        self.footer_dot = self._panel(
            self.screen,
            canvas_x,
            footer_y + max(9, int(11 * self.scale)),
            8,
            8,
            self.WARN,
            self.WARN,
            4,
        )
        self.footer_status = self._label(
            self.screen,
            "WAITING FOR HEALTH DATA",
            canvas_x + 16,
            footer_y + max(5, int(7 * self.scale)),
            self.MUTED,
            self.font_small,
        )
        self.updated_label = self._label(
            self.screen,
            "UPDATED --:--:--",
            canvas_x + canvas_width - 150,
            footer_y + max(5, int(7 * self.scale)),
            self.DIM,
            self.font_small,
        )

        self.camera_page_widgets = {}
        self.update_view = self._build_update_view(canvas_x, canvas_width, margin)
        self.capture_view = self._build_capture_view(canvas_x, canvas_width, margin)
        self.camera_views = {
            "tool": self._build_camera_view("tool", canvas_x, canvas_width, margin),
            "workspace": self._build_camera_view(
                "workspace", canvas_x, canvas_width, margin
            ),
        }
        self.system_view = self._build_system_view(
            canvas_x,
            canvas_width,
            margin,
        )
        self.robot_metrics_view = self._build_robot_metrics_view(
            canvas_x,
            canvas_width,
            margin,
        )
        self.safety_config_view = self._build_safety_config_view(
            canvas_x,
            canvas_width,
            margin,
        )
        self.metrics_view = self._build_metrics_view(
            canvas_x,
            canvas_width,
            margin,
        )
        self.operations_view = self._build_operations_view(
            canvas_x,
            canvas_width,
            margin,
        )
        self.production_view = self._build_production_view(
            canvas_x,
            canvas_width,
            margin,
        )
        self.manual_review_view = self._build_manual_review_view(
            canvas_x,
            canvas_width,
            margin,
        )
        self.digital_twin_view = self._build_digital_twin_view(
            canvas_x,
            canvas_width,
            margin,
        )
        self.workspace_teach_view = self._build_workspace_teach_view(
            canvas_x,
            canvas_width,
            margin,
        )
        self.tenant_auth_view = self._build_tenant_auth_view(
            canvas_x,
            canvas_width,
            margin,
        )
        self.hand_training_view = self._build_hand_training_view(
            canvas_x,
            canvas_width,
            margin,
        )
        self.home_view = self._build_home_view(
            canvas_x,
            canvas_width,
            margin,
        )
        self._overlays = {
            "home": self.home_view,
            "tool": self.camera_views["tool"],
            "workspace": self.camera_views["workspace"],
            "system": self.system_view,
            "robot_metrics": self.robot_metrics_view,
            "safety_config": self.safety_config_view,
            "capture": self.capture_view,
            "updates": self.update_view,
            "metrics": self.metrics_view,
            "operations": self.operations_view,
            "production": self.production_view,
            "manual_review": self.manual_review_view,
            "digital_twin": self.digital_twin_view,
            "workspace_teach": self.workspace_teach_view,
            "tenant_auth": self.tenant_auth_view,
            "hand_training": self.hand_training_view,
        }
        self.software_stop_nav = self._build_software_stop_nav(
            canvas_x,
            canvas_width,
            margin,
        )
        # Build this last so its opaque, local-only surface receives the wake
        # tap instead of allowing that first tap to reach an action beneath it.
        self.screensaver_overlay = self._build_screensaver_overlay()
        self._activate_view(self._active_view, invalidate=False)

        load_screen = getattr(lv, "screen_load", None) or getattr(lv, "scr_load")
        load_screen(self.screen)
        # The opaque saver is the final widget and is moved to the foreground
        # again after loading the new root. No action callback is accepted
        # until that ordering has succeeded for this exact layout generation.
        self._layout_input_ready = self._foreground_screensaver_overlay()

    def _queue_resolution_change(self, _event=None):
        # Never rebuild the active screen from inside LVGL's display event
        # dispatch.  The short timer below applies it after the SDL handler has
        # completed the framebuffer resize.
        self._layout_pending = True

    def _display_dimensions(self):
        getters = (
            (
                getattr(self.display, "get_horizontal_resolution", None),
                getattr(self.display, "get_vertical_resolution", None),
                False,
            ),
            (
                getattr(self.lv, "display_get_horizontal_resolution", None),
                getattr(self.lv, "display_get_vertical_resolution", None),
                True,
            ),
        )
        for horizontal, vertical, takes_display in getters:
            if not callable(horizontal) or not callable(vertical):
                continue
            try:
                if takes_display:
                    width = int(horizontal(self.display))
                    height = int(vertical(self.display))
                else:
                    width = int(horizontal())
                    height = int(vertical())
            except Exception:
                continue
            if width > 0 and height > 0:
                return width, height
        try:
            width = int(self.screen.get_width())
            height = int(self.screen.get_height())
        except Exception:
            return self.width, self.height
        if width > 0 and height > 0:
            return width, height
        return self.width, self.height

    def _check_resolution(self, _timer=None):
        width, height = self._display_dimensions()
        if width == self.width and height == self.height:
            self._layout_pending = False
            return
        # Reject transient/invalid SDL dimensions while a compositor is
        # mapping the window.  The configured frontend minimum is 640x400.
        if width < 640 or height < 400:
            return
        if not self._retry_failed_layout_deletes():
            # Keep the current actionable tree instead of accumulating an
            # unbounded number of undeletable screens/callback generations.
            return
        old_screen = self.screen
        old_callbacks = tuple(getattr(self, "_guarded_click_callbacks", ()))
        wake_callback = getattr(self, "_screensaver_wake_callback", None)
        if callable(wake_callback):
            old_callbacks = old_callbacks + (wake_callback,)
        snapshot = self._snapshot_rebuild_state()
        self._clear_tenant_password(getattr(self, "tenant_auth_password_input", None))
        self._set_dimensions(width, height)
        self._layout_pending = False
        self._build_screen()
        self._apply(self._last_view)
        # _apply() may consume old health-derived state. Restore the bounded
        # operator/action boundary captured immediately before reconstruction,
        # then render those optimistic views into the new widgets. This never
        # publishes or replays a broker request.
        self._restore_rebuild_state(snapshot)
        if getattr(self, "_motion_stop_latched", False):
            self._last_capture_view = _latched_stop_capture(
                self._last_capture_view,
                self._last_capture_view,
            )
        self._rerender_rebuild_state()
        self._enforce_screensaver_visibility()
        if getattr(self, "_screensaver_active", False):
            self._layout_input_ready = bool(
                self._layout_input_ready and self._foreground_screensaver_overlay()
            )
        self._retire_replaced_layout(old_screen, old_callbacks)
        screen = getattr(self, "screen", None)
        invalidate = getattr(screen, "invalidate", None)
        if callable(invalidate):
            invalidate()

    def _disable_scroll(self, item):
        flags = getattr(self.lv.obj, "FLAG", None)
        if flags is not None and hasattr(flags, "SCROLLABLE"):
            item.remove_flag(flags.SCROLLABLE)

    def _label(self, parent, text, x, y, color, font=None):
        label = self.lv.label(parent)
        label.set_text(text)
        label.set_pos(x, y)
        label.set_style_text_color(self.lv.color_hex(color), 0)
        if font is not None:
            label.set_style_text_font(font, 0)
        return label

    def _panel(self, parent, x, y, width, height, fill, border, radius):
        panel = self.lv.obj(parent)
        panel.set_pos(x, y)
        panel.set_size(width, height)
        panel.set_style_bg_color(self.lv.color_hex(fill), 0)
        panel.set_style_bg_opa(self.lv.OPA.COVER, 0)
        panel.set_style_border_width(1 if border != fill else 0, 0)
        panel.set_style_border_color(self.lv.color_hex(border), 0)
        panel.set_style_radius(radius, 0)
        panel.set_style_pad_all(0, 0)
        self._disable_scroll(panel)
        return panel

    def _new_twin_line(self, parent, color, width=2):
        """Create one bounded LVGL line and retain its native point buffer."""

        line_type = getattr(self.lv, "line", None)
        if not callable(line_type):
            return {"line": None, "points": []}
        try:
            line = line_type(parent)
            set_color = getattr(line, "set_style_line_color", None)
            if callable(set_color):
                set_color(self.lv.color_hex(color), 0)
            set_width = getattr(line, "set_style_line_width", None)
            if callable(set_width):
                set_width(width, 0)
            set_rounded = getattr(line, "set_style_line_rounded", None)
            if callable(set_rounded):
                set_rounded(True, 0)
            line.add_flag(self.lv.obj.FLAG.HIDDEN)
            return {"line": line, "points": []}
        except Exception:
            return {"line": None, "points": []}

    def _set_twin_segment(self, slot, first, second):
        line = _mapping(slot).get("line")
        if line is None:
            return False
        # LVGL's MicroPython binding keeps the Python point array by reference.
        # Store it beside the widget for the complete lifetime of that segment.
        points = [
            {"x": int(first[0]), "y": int(first[1])},
            {"x": int(second[0]), "y": int(second[1])},
        ]
        slot["points"] = points
        try:
            line.set_points(points, 2)
            line.remove_flag(self.lv.obj.FLAG.HIDDEN)
            return True
        except Exception:
            try:
                line.add_flag(self.lv.obj.FLAG.HIDDEN)
            except Exception:
                pass
            return False

    def _hide_twin_segment(self, slot):
        line = _mapping(slot).get("line")
        if line is not None:
            try:
                line.add_flag(self.lv.obj.FLAG.HIDDEN)
            except Exception:
                pass

    def _make_clickable(self, item, callback):
        layout_generation = int(getattr(self, "_layout_generation", 0))

        def guarded_callback(event):
            if layout_generation != int(
                getattr(self, "_layout_generation", 0)
            ) or not getattr(self, "_layout_input_ready", True):
                # A callback retained by an undeletable, replaced widget tree
                # is permanently inert. It cannot navigate or cross a broker
                # boundary in the new layout generation.
                return
            if not self._clicked(event):
                return
            if getattr(self, "_screensaver_active", False):
                self._wake_screensaver(event)
                return
            uncertain = bool(getattr(self, "_input_uncertain_contact", False))
            if getattr(self, "_screensaver_wake_guard", False) or uncertain:
                # LVGL normally targets only the top overlay.  Keep this
                # one-tick guard as a second boundary in case a binding also
                # bubbles the same release/click to a control underneath.  A
                # reconnect/restart contact is consumed for the same reason.
                self._record_interaction()
                if uncertain:
                    self._clear_uncertain_input_contact()
                return
            self._record_interaction()
            callback(event)

        callbacks = getattr(self, "_guarded_click_callbacks", None)
        if callbacks is None:
            callbacks = []
            self._guarded_click_callbacks = callbacks
        callbacks.append(guarded_callback)
        item.add_flag(self.lv.obj.FLAG.CLICKABLE)
        item.add_event_cb(guarded_callback, self.lv.EVENT.CLICKED, None)

    def _foreground_screensaver_overlay(self):
        overlay = getattr(self, "screensaver_overlay", None)
        move_foreground = getattr(overlay, "move_foreground", None)
        if not callable(move_foreground):
            self._screensaver_foreground_generation = -1
            return False
        try:
            move_foreground()
        except Exception:
            self._screensaver_foreground_generation = -1
            return False
        self._screensaver_foreground_generation = int(
            getattr(self, "_layout_generation", 0)
        )
        return True

    def _build_screensaver_overlay(self):
        overlay = self._panel(
            self.screen,
            0,
            0,
            self.width,
            self.height,
            0x000000,
            0x000000,
            0,
        )
        overlay.add_flag(self.lv.obj.FLAG.CLICKABLE)
        layout_generation = int(getattr(self, "_layout_generation", 0))

        def guarded_wake(event):
            if layout_generation != int(
                getattr(self, "_layout_generation", 0)
            ) or not getattr(self, "_layout_input_ready", True):
                return False
            return self._wake_screensaver(event)

        self._screensaver_wake_callback = guarded_wake
        overlay.add_event_cb(
            self._screensaver_wake_callback,
            self.lv.EVENT.CLICKED,
            None,
        )
        if not getattr(self, "_screensaver_active", False):
            overlay.add_flag(self.lv.obj.FLAG.HIDDEN)
        return overlay

    def _build_back_header(self, overlay, canvas_x, canvas_width, margin, title):
        nav_height = max(44, int(46 * min(self.scale, 1.3)))
        back_button = self._panel(
            overlay,
            canvas_x,
            margin,
            max(118, int(124 * min(self.scale, 1.2))),
            nav_height,
            self.CARD,
            self.ACCENT,
            nav_height // 2,
        )
        back_label = self._label(
            back_button,
            "<  START",
            0,
            0,
            self.ACCENT,
            self.font_body,
        )
        back_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._make_clickable(back_button, self._show_home)
        self._label(
            overlay,
            title,
            canvas_x + max(142, int(150 * min(self.scale, 1.2))),
            margin + max(7, int(8 * min(self.scale, 1.2))),
            self.TEXT,
            self.font_title,
        )
        return nav_height

    def _build_home_view(self, canvas_x, canvas_width, margin):
        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        self._label(
            overlay,
            "LABCOBOT TOUCH CONTROL",
            canvas_x,
            margin,
            self.TEXT,
            self.font_title,
        )
        subtitle = self._label(
            overlay,
            "Twin, Workspace Teach und tenantgebundener SupraTix Login",
            canvas_x,
            margin + max(30, int(32 * min(self.scale, 1.3))),
            self.MUTED,
            self.font_small,
        )
        subtitle.set_width(canvas_width)

        start_y = margin + max(66, int(70 * min(self.scale, 1.25)))
        column_gap = max(10, int(17 * min(self.scale, 1.25)))
        row_gap = max(25, int(32 * min(self.scale, 1.25)))
        self.launcher_buttons = {}
        callbacks = {
            "tool": self._show_tool_stream,
            "workspace": self._show_workspace_stream,
            "system": self._show_system,
            "capture": self._show_capture,
            "updates": self._show_updates,
            "metrics": self._show_metrics,
            "digital_twin": self._show_digital_twin,
            "workspace_teach": self._show_workspace_teach,
            "tenant_auth": self._show_tenant_auth,
            "hand_training": self._show_hand_training,
            "production": self._show_production,
        }
        columns_per_row = 6 if len(LAUNCHER_ITEMS) > 10 else 5 if len(LAUNCHER_ITEMS) > 8 else 4
        row_count = (len(LAUNCHER_ITEMS) + columns_per_row - 1) // columns_per_row
        width_limit = (
            canvas_width - (column_gap * (columns_per_row - 1))
        ) // columns_per_row
        height_limit = (
            self.height - margin - start_y - (row_gap * max(0, row_count - 1))
        ) // max(1, row_count)
        button_diameter = max(
            72,
            min(
                144,
                int(132 * min(self.scale, 1.25)),
                width_limit,
                height_limit,
            ),
        )
        row_pitch = button_diameter + row_gap
        for index, item in enumerate(LAUNCHER_ITEMS):
            key, number, title = item
            row = index // columns_per_row
            column = index % columns_per_row
            items_in_row = min(
                columns_per_row,
                len(LAUNCHER_ITEMS) - (row * columns_per_row),
            )
            row_width = (button_diameter * items_in_row) + (
                column_gap * (items_in_row - 1)
            )
            row_start_x = canvas_x + ((canvas_width - row_width) // 2)
            x = row_start_x + (column * (button_diameter + column_gap))
            y = start_y + (row * row_pitch)
            button = self._panel(
                overlay,
                x,
                y,
                button_diameter,
                button_diameter,
                self.CARD,
                self.BORDER,
                button_diameter // 2,
            )
            number_label = self._label(
                button,
                number,
                0,
                max(18, int(20 * min(self.scale, 1.2))),
                self.ACCENT,
                self.font_title,
            )
            number_label.set_width(button_diameter)
            number_label.set_style_text_align(self.lv.TEXT_ALIGN.CENTER, 0)
            title_label = self._label(
                button,
                title,
                0,
                max(40, int(52 * min(self.scale, 1.2))),
                self.TEXT,
                self.font_small,
            )
            title_label.set_width(button_diameter)
            title_label.set_style_text_align(self.lv.TEXT_ALIGN.CENTER, 0)
            status = self._label(
                button,
                "WAIT",
                0,
                button_diameter - max(24, int(30 * min(self.scale, 1.2))),
                self.DIM,
                self.font_small,
            )
            status.set_width(button_diameter)
            status.set_style_text_align(self.lv.TEXT_ALIGN.CENTER, 0)
            callback = callbacks[key]
            self._make_clickable(button, callback)
            self.launcher_buttons[key] = {
                "button": button,
                "status": status,
                "callback": callback,
            }
        return overlay

    def _build_camera_view(self, role, canvas_x, canvas_width, margin):
        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        title = (
            "VIDEOSTREAM 1 - TOOL" if role == "tool" else "VIDEOSTREAM 2 - WORKSPACE"
        )
        nav_height = self._build_back_header(
            overlay, canvas_x, canvas_width, margin, title
        )
        card_y = margin + nav_height + max(15, int(17 * self.scale))
        card_height = self.height - card_y - margin
        card = self._panel(
            overlay,
            canvas_x,
            card_y,
            canvas_width,
            card_height,
            self.CARD,
            self.BORDER,
            16,
        )
        pad = max(18, int(22 * min(self.scale, 1.3)))
        headline = self._label(
            card,
            "WAITING FOR CAMERA",
            pad,
            pad,
            self.WARN,
            self.font_title,
        )
        detail = self._label(
            card,
            "Waiting for fresh OAK-D Lite frames",
            pad,
            pad + 38,
            self.MUTED,
            self.font_body,
        )
        metadata = self._label(
            card,
            "ROLE -- | BACKEND -- | ID --\nAGE -- | SEQ --",
            pad,
            pad + 68,
            self.DIM,
            self.font_small,
        )
        metadata.set_width(canvas_width - (pad * 2))
        preview_y = pad + 108
        preview_width = canvas_width - (pad * 2)
        retention_height = 22
        preview_height = card_height - preview_y - pad - retention_height
        preview = self._panel(
            card,
            pad,
            preview_y,
            preview_width,
            preview_height,
            self.PANEL,
            self.BORDER,
            12,
        )
        preview_label = self._label(
            preview,
            "LOADING VOLATILE LIVE PREVIEW\n\nNo frame on this page is saved to DataHub.\nDataset capture starts only on its confirmation page.",
            0,
            max(48, int(58 * min(self.scale, 1.3))),
            self.MUTED,
            self.font_body,
        )
        preview_label.set_width(canvas_width - (pad * 2))
        preview_label.set_style_text_align(self.lv.TEXT_ALIGN.CENTER, 0)
        image = self.lv.image(preview)
        image.set_pos(0, 0)
        image.set_size(preview_width, preview_height)
        image.add_flag(self.lv.obj.FLAG.HIDDEN)
        retention = self._label(
            card,
            "VOLATILE LIVE PREVIEW | NOT SAVED TO DATASET",
            pad,
            preview_y + preview_height + 4,
            self.WARN,
            self.font_small,
        )
        retention.set_width(preview_width)
        retention.set_style_text_align(self.lv.TEXT_ALIGN.CENTER, 0)
        self.camera_page_widgets[role] = {
            "headline": headline,
            "detail": detail,
            "metadata": metadata,
            "preview": preview,
            "preview_label": preview_label,
            "retention": retention,
            "image": image,
            "preview_width": preview_width,
            "preview_height": preview_height,
        }
        return overlay

    def _build_system_view(self, canvas_x, canvas_width, margin):
        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        nav_height = self._build_back_header(
            overlay, canvas_x, canvas_width, margin, "xARM ROBOTERSTEUERUNG"
        )
        top = margin + nav_height + max(14, int(16 * self.scale))
        gap = max(12, int(14 * self.scale))
        content_height = self.height - top - margin
        upper_height = max(218, int(224 * min(self.scale, 1.2)))
        xarm_width = int((canvas_width - gap) * 0.57)
        gate_width = canvas_width - xarm_width - gap

        xarm_panel = self._panel(
            overlay,
            canvas_x,
            top,
            xarm_width,
            upper_height,
            self.CARD,
            self.BORDER,
            14,
        )
        pad = max(16, int(18 * min(self.scale, 1.25)))
        self.system_xarm_eyebrow = self._label(
            xarm_panel,
            "xARM CONTROLLER / RUNTIME ROLE UNKNOWN",
            pad,
            pad,
            self.DIM,
            self.font_small,
        )
        self.system_xarm_headline = self._label(
            xarm_panel,
            "UNAVAILABLE",
            pad,
            pad + 30,
            self.TEXT,
            self.font_title,
        )
        self.system_xarm_detail = self._label(
            xarm_panel,
            "No bounded controller telemetry",
            pad,
            pad + 68,
            self.MUTED,
            self.font_body,
        )
        self.system_xarm_guidance = self._label(
            xarm_panel,
            "Robot readiness is not verified.",
            pad,
            pad + 104,
            self.WARN,
            self.font_body,
        )
        self.system_xarm_guidance.set_width(xarm_width - (pad * 2))
        self.system_search_review = self._label(
            xarm_panel,
            "LETZTES ZIEL: NONE / CONF --",
            pad,
            pad + 154,
            self.DIM,
            self.font_small,
        )
        self.system_search_review.set_width(xarm_width - (pad * 2))

        gates = self._panel(
            overlay,
            canvas_x + xarm_width + gap,
            top,
            gate_width,
            upper_height,
            self.CARD,
            self.BORDER,
            14,
        )
        self._label(gates, "ROBOT MOTION GATE", pad, pad, self.DIM, self.font_small)
        self.system_motion_gate = self._label(
            gates, "NOT VERIFIED", pad, pad + 28, self.TEXT, self.font_body
        )
        self.system_motion_detail = self._label(
            gates,
            "Robot motion gate unavailable",
            pad,
            pad + 55,
            self.MUTED,
            self.font_small,
        )
        self.system_motion_detail.set_width(gate_width - (pad * 2))
        divider_y = pad + 91
        self._panel(
            gates,
            pad,
            divider_y,
            gate_width - (pad * 2),
            1,
            self.BORDER,
            self.BORDER,
            0,
        )
        self._label(
            gates,
            "WORKCELL / CAPTURE GATE",
            pad,
            divider_y + 14,
            self.DIM,
            self.font_small,
        )
        self.system_capture_gate = self._label(
            gates,
            "CAPTURE NICHT KONFIGURIERT",
            pad,
            divider_y + 41,
            self.TEXT,
            self.font_body,
        )
        self.system_capture_detail = self._label(
            gates,
            "Capture + DataHub not configured",
            pad,
            divider_y + 68,
            self.MUTED,
            self.font_small,
        )
        self.system_capture_detail.set_width(gate_width - (pad * 2))

        action_y = top + upper_height + gap
        action_height = max(112, content_height - upper_height - gap)
        action_panel = self._panel(
            overlay,
            canvas_x,
            action_y,
            canvas_width,
            action_height,
            self.PANEL,
            self.BORDER,
            14,
        )
        stage_y = max(10, int(12 * min(self.scale, 1.2)))
        self.system_search_stage = self._label(
            action_panel,
            "ROBOTER-STEUERUNG  |  0 / 4  STATUS UNBEKANNT",
            pad,
            stage_y,
            self.DIM,
            self.font_small,
        )
        self.system_search_stage.set_width(canvas_width - (pad * 2))
        progress_y = stage_y + max(24, int(25 * min(self.scale, 1.2)))
        progress_height = max(8, int(9 * min(self.scale, 1.2)))
        self.system_search_progress_width = canvas_width - (pad * 2)
        self.system_search_progress_height = progress_height
        self.system_search_progress_track = self._panel(
            action_panel,
            pad,
            progress_y,
            self.system_search_progress_width,
            progress_height,
            self.BORDER,
            self.BORDER,
            progress_height // 2,
        )
        self.system_search_progress_fill = self._panel(
            action_panel,
            pad,
            progress_y,
            1,
            progress_height,
            self.DIM,
            self.DIM,
            progress_height // 2,
        )

        action_button_width = min(300, int(canvas_width * 0.32))
        action_button_height = max(48, int(50 * min(self.scale, 1.2)))
        control_y = max(
            progress_y + progress_height + 12,
            action_height - pad - action_button_height,
        )
        self.system_run_button = self._panel(
            action_panel,
            pad,
            control_y,
            action_button_width,
            action_button_height,
            self.DIM,
            self.DIM,
            action_button_height // 2,
        )
        self.system_run_button_label = self._label(
            self.system_run_button,
            "ROBOTERLAUF GESPERRT",
            0,
            0,
            self.INK,
            self.font_body,
        )
        self.system_run_button_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._system_run_callback = self._system_primary_click
        self._make_clickable(self.system_run_button, self._system_run_callback)
        self.system_run_detail = self._label(
            action_panel,
            "Konfigurierter Kamera-Suchpfad",
            pad + action_button_width + gap,
            control_y + max(5, int(6 * min(self.scale, 1.2))),
            self.MUTED,
            self.font_small,
        )
        stop_button_width = min(210, int(canvas_width * 0.22))
        self.system_run_detail.set_width(
            canvas_width
            - action_button_width
            - stop_button_width
            - (pad * 2)
            - (gap * 2)
        )
        self.system_stop_button = self._panel(
            action_panel,
            canvas_width - pad - stop_button_width,
            control_y,
            stop_button_width,
            action_button_height,
            self.CARD,
            self.DANGER,
            action_button_height // 2,
        )
        self.system_stop_button_label = self._label(
            self.system_stop_button,
            "SOFTWARE STOP",
            0,
            0,
            self.DANGER,
            self.font_body,
        )
        self.system_stop_button_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._system_stop_callback = self._software_stop_click
        self._make_clickable(self.system_stop_button, self._system_stop_callback)

        metrics_button_width = max(180, int(190 * min(self.scale, 1.2)))
        metrics_button_height = max(38, int(40 * min(self.scale, 1.2)))
        metrics_button_y = upper_height - pad - metrics_button_height
        self.system_metrics_button = self._panel(
            xarm_panel,
            xarm_width - pad - metrics_button_width,
            metrics_button_y,
            metrics_button_width,
            metrics_button_height,
            self.CARD,
            self.ACCENT,
            metrics_button_height // 2,
        )
        self.system_metrics_button_label = self._label(
            self.system_metrics_button,
            "ROBOT METRICS >",
            0,
            0,
            self.ACCENT,
            self.font_small,
        )
        self.system_metrics_button_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._open_robot_metrics_callback = self._show_robot_metrics
        self._make_clickable(
            self.system_metrics_button,
            self._open_robot_metrics_callback,
        )
        # Share the final row with the last target summary.  Keeping the
        # button out of the headline area prevents overlap at 1024x600 while
        # preserving a large touch target.
        self.system_search_review.set_width(
            xarm_width - (pad * 2) - metrics_button_width - gap
        )
        return overlay

    def _build_digital_twin_view(self, canvas_x, canvas_width, margin):
        """Build a read-only, fixed-projection digital-twin inspection page."""

        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        nav_height = self._build_back_header(
            overlay,
            canvas_x,
            canvas_width,
            margin,
            "3D DIGITALER ZWILLING",
        )
        top = margin + nav_height + max(10, int(12 * self.scale))
        gap = max(8, int(10 * min(self.scale, 1.25)))
        content_height = self.height - top - margin
        action_height = max(68, int(74 * min(self.scale, 1.2)))
        body_height = max(150, content_height - action_height - gap)
        visual_width = int((canvas_width - gap) * 0.62)
        gate_width = canvas_width - visual_width - gap
        pad = max(10, int(14 * min(self.scale, 1.2)))

        visual = self._panel(
            overlay,
            canvas_x,
            top,
            visual_width,
            body_height,
            self.CARD,
            self.BORDER,
            14,
        )
        self.twin_headline = self._label(
            visual,
            "DIGITAL TWIN UNAVAILABLE",
            pad,
            pad,
            self.DIM,
            self.font_body,
        )
        self.twin_headline.set_width(visual_width - (pad * 2))
        self.twin_pose_detail = self._label(
            visual,
            "POSE -- | FRAME xarm_base_mm | MODEL --",
            pad,
            pad + max(23, int(25 * min(self.scale, 1.2))),
            self.MUTED,
            self.font_small,
        )
        self.twin_pose_detail.set_width(visual_width - (pad * 2))

        projection_y = pad + max(46, int(49 * min(self.scale, 1.2)))
        projection_gap = max(5, int(6 * min(self.scale, 1.2)))
        projection_height = max(28, int(30 * min(self.scale, 1.2)))
        projection_width = (visual_width - (pad * 2) - (projection_gap * 2)) // 3
        self.twin_projection_buttons = {}
        self._twin_projection_callbacks = []
        projection_labels = (
            ("isometric", "ISOMETRIC"),
            ("top", "TOP"),
            ("front", "FRONT"),
        )
        for index, (projection, title) in enumerate(projection_labels):
            button = self._panel(
                visual,
                pad + (index * (projection_width + projection_gap)),
                projection_y,
                projection_width,
                projection_height,
                self.PANEL,
                self.BORDER,
                projection_height // 2,
            )
            label = self._label(button, title, 0, 0, self.DIM, self.font_small)
            label.align(self.lv.ALIGN.CENTER, 0, 0)

            def select_projection(event, selected=projection):
                self._select_twin_projection(selected, event)

            self._twin_projection_callbacks.append(select_projection)
            self._make_clickable(button, select_projection)
            self.twin_projection_buttons[projection] = {
                "button": button,
                "label": label,
            }

        viewport_y = (
            projection_y + projection_height + max(7, int(8 * min(self.scale, 1.2)))
        )
        viewport_height = max(64, body_height - viewport_y - pad)
        viewport_width = visual_width - (pad * 2)
        self.twin_viewport = self._panel(
            visual,
            pad,
            viewport_y,
            viewport_width,
            viewport_height,
            self.PANEL,
            self.BORDER,
            10,
        )
        self.twin_viewport_width = viewport_width
        self.twin_viewport_height = viewport_height
        self.twin_renderer_notice = self._label(
            self.twin_viewport,
            "WAITING FOR VALIDATED 3D GEOMETRY",
            0,
            max(18, (viewport_height // 2) - 8),
            self.DIM,
            self.font_small,
        )
        self.twin_renderer_notice.set_width(viewport_width)
        self.twin_renderer_notice.set_style_text_align(
            self.lv.TEXT_ALIGN.CENTER,
            0,
        )

        self.twin_workspace_lines = [
            self._new_twin_line(self.twin_viewport, self.BORDER, 1)
            for _index in range(12)
        ]
        self.twin_arm_lines = [
            self._new_twin_line(self.twin_viewport, self.ACCENT, 4)
            for _index in range(6)
        ]
        self.twin_path_lines = [
            self._new_twin_line(self.twin_viewport, self.OK, 2) for _index in range(31)
        ]
        self.twin_axis_lines = [
            self._new_twin_line(self.twin_viewport, color, 2)
            for color in (self.DANGER, self.OK, self.ACCENT)
        ]
        all_line_slots = (
            self.twin_workspace_lines
            + self.twin_arm_lines
            + self.twin_path_lines
            + self.twin_axis_lines
        )
        self.twin_line_supported = bool(
            all(slot.get("line") is not None for slot in all_line_slots)
        )
        joint_size = max(7, int(8 * min(self.scale, 1.2)))
        self.twin_joint_size = joint_size
        self.twin_joint_markers = []
        for _index in range(7):
            marker = self._panel(
                self.twin_viewport,
                0,
                0,
                joint_size,
                joint_size,
                self.ACCENT,
                self.TEXT,
                joint_size // 2,
            )
            marker.add_flag(self.lv.obj.FLAG.HIDDEN)
            self.twin_joint_markers.append(marker)
        obstacle_size = max(9, int(10 * min(self.scale, 1.2)))
        self.twin_obstacle_size = obstacle_size
        self.twin_obstacle_marker = self._panel(
            self.twin_viewport,
            0,
            0,
            obstacle_size,
            obstacle_size,
            self.DANGER,
            self.DANGER,
            obstacle_size // 2,
        )
        self.twin_obstacle_marker.add_flag(self.lv.obj.FLAG.HIDDEN)

        gates = self._panel(
            overlay,
            canvas_x + visual_width + gap,
            top,
            gate_width,
            body_height,
            self.CARD,
            self.BORDER,
            14,
        )
        self._label(
            gates,
            "DUAL-CAM SAFETY GATES",
            pad,
            pad,
            self.DIM,
            self.font_small,
        )
        self.twin_gate_summary = self._label(
            gates,
            "0 / 8 VERIFIED",
            pad,
            pad + max(23, int(25 * min(self.scale, 1.2))),
            self.WARN,
            self.font_body,
        )
        self.twin_camera_summary = self._label(
            gates,
            "TOOL -- | WORKSPACE --",
            pad,
            pad + max(48, int(51 * min(self.scale, 1.2))),
            self.MUTED,
            self.font_small,
        )
        self.twin_camera_summary.set_width(gate_width - (pad * 2))
        rows_y = pad + max(75, int(78 * min(self.scale, 1.2)))
        available_rows = max(80, body_height - rows_y - pad)
        row_height = max(17, available_rows // 8)
        self.twin_gate_rows = []
        for index in range(8):
            label = self._label(
                gates,
                "--  GATE",
                pad,
                rows_y + (index * row_height),
                self.DIM,
                self.font_small,
            )
            label.set_width(gate_width - (pad * 2))
            self.twin_gate_rows.append(label)

        action = self._panel(
            overlay,
            canvas_x,
            top + body_height + gap,
            canvas_width,
            action_height,
            self.PANEL,
            self.BORDER,
            14,
        )
        action_pad = max(10, int(12 * min(self.scale, 1.2)))
        button_width = min(300, int(canvas_width * 0.32))
        button_height = max(44, action_height - (action_pad * 2))
        self.twin_action_stage = self._label(
            action,
            "READ-ONLY TWIN | SEARCH GESPERRT",
            action_pad,
            action_pad,
            self.DIM,
            self.font_small,
        )
        self.twin_action_stage.set_width(canvas_width - button_width - (action_pad * 3))
        self.twin_action_detail = self._label(
            action,
            "Keine freigegebene 3D-Trajektorie",
            action_pad,
            action_pad + max(21, int(22 * min(self.scale, 1.2))),
            self.MUTED,
            self.font_small,
        )
        self.twin_action_detail.set_width(
            canvas_width - button_width - (action_pad * 3)
        )
        self.twin_action_button = self._panel(
            action,
            canvas_width - action_pad - button_width,
            action_pad,
            button_width,
            button_height,
            self.DIM,
            self.DIM,
            button_height // 2,
        )
        self.twin_action_button_label = self._label(
            self.twin_action_button,
            "SEARCH GESPERRT",
            0,
            0,
            self.INK,
            self.font_body,
        )
        self.twin_action_button_label.align(self.lv.ALIGN.CENTER, 0, 0)
        # This is the existing reviewed Search callback.  The twin creates no
        # transport lane, endpoint, free-form target, jog, or robot command.
        self._twin_search_callback = self._system_primary_click
        self._make_clickable(self.twin_action_button, self._twin_search_callback)
        return overlay

    def _build_workspace_teach_view(self, canvas_x, canvas_width, margin):
        """Build the guided, read-only TCP workspace commissioning page."""

        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        nav_height = self._build_back_header(
            overlay,
            canvas_x,
            canvas_width,
            margin,
            "LITE6 WORKSPACE TEACH",
        )
        top = margin + nav_height + max(9, int(10 * self.scale))
        gap = max(8, int(10 * min(self.scale, 1.25)))
        content_height = self.height - top - margin
        action_height = max(78, int(82 * min(self.scale, 1.2)))
        body_height = max(160, content_height - action_height - gap)
        visual_width = int((canvas_width - gap) * 0.56)
        guidance_width = canvas_width - visual_width - gap
        pad = max(9, int(12 * min(self.scale, 1.2)))

        visual = self._panel(
            overlay,
            canvas_x,
            top,
            visual_width,
            body_height,
            self.CARD,
            self.BORDER,
            14,
        )
        self.workspace_teach_headline = self._label(
            visual,
            "WORKSPACE TEACH UNAVAILABLE",
            pad,
            pad,
            self.DIM,
            self.font_body,
        )
        self.workspace_teach_headline.set_width(visual_width - (pad * 2))
        self.workspace_teach_progress = self._label(
            visual,
            "0 / 6 GRENZEN | FRAME --",
            pad,
            pad + max(23, int(25 * min(self.scale, 1.2))),
            self.MUTED,
            self.font_small,
        )
        self.workspace_teach_progress.set_width(visual_width - (pad * 2))

        viewport_y = pad + max(48, int(51 * min(self.scale, 1.2)))
        viewport_height = max(72, body_height - viewport_y - pad)
        viewport_width = visual_width - (pad * 2)
        self.workspace_teach_viewport = self._panel(
            visual,
            pad,
            viewport_y,
            viewport_width,
            viewport_height,
            self.PANEL,
            self.BORDER,
            10,
        )
        self.workspace_teach_viewport_width = viewport_width
        self.workspace_teach_viewport_height = viewport_height
        self.workspace_teach_renderer_notice = self._label(
            self.workspace_teach_viewport,
            "WAITING FOR VALIDATED WORKSPACE SNAPSHOT",
            0,
            max(18, (viewport_height // 2) - 8),
            self.DIM,
            self.font_small,
        )
        self.workspace_teach_renderer_notice.set_width(viewport_width)
        self.workspace_teach_renderer_notice.set_style_text_align(
            self.lv.TEXT_ALIGN.CENTER,
            0,
        )
        self.workspace_teach_hard_lines = [
            self._new_twin_line(self.workspace_teach_viewport, self.BORDER, 2)
            for _index in range(12)
        ]
        self.workspace_teach_captured_lines = [
            self._new_twin_line(self.workspace_teach_viewport, self.ACCENT, 2)
            for _index in range(24)
        ]
        teach_lines = (
            self.workspace_teach_hard_lines + self.workspace_teach_captured_lines
        )
        self.workspace_teach_line_supported = bool(
            all(slot.get("line") is not None for slot in teach_lines)
        )
        tcp_size = max(10, int(11 * min(self.scale, 1.2)))
        self.workspace_teach_tcp_size = tcp_size
        self.workspace_teach_tcp_marker = self._panel(
            self.workspace_teach_viewport,
            0,
            0,
            tcp_size,
            tcp_size,
            self.WARN,
            self.TEXT,
            tcp_size // 2,
        )
        self.workspace_teach_tcp_marker.add_flag(self.lv.obj.FLAG.HIDDEN)

        guidance = self._panel(
            overlay,
            canvas_x + visual_width + gap,
            top,
            guidance_width,
            body_height,
            self.CARD,
            self.BORDER,
            14,
        )
        self.workspace_teach_mode = self._label(
            guidance,
            "MODE 2 EXTERN AKTIVIEREN",
            pad,
            pad,
            self.WARN,
            self.font_body,
        )
        self.workspace_teach_mode.set_width(guidance_width - (pad * 2))
        self.workspace_teach_guidance_title = self._label(
            guidance,
            "SESSION NICHT GESTARTET",
            pad,
            pad + max(30, int(33 * min(self.scale, 1.2))),
            self.TEXT,
            self.font_body,
        )
        self.workspace_teach_guidance_title.set_width(guidance_width - (pad * 2))
        self.workspace_teach_guidance_detail = self._label(
            guidance,
            "Mode 2 wird ausschliesslich am Controller aktiviert.",
            pad,
            pad + max(57, int(61 * min(self.scale, 1.2))),
            self.MUTED,
            self.font_small,
        )
        self.workspace_teach_guidance_detail.set_width(guidance_width - (pad * 2))
        rows_y = pad + max(101, int(106 * min(self.scale, 1.2)))
        rows_height = max(78, body_height - rows_y - pad - 49)
        row_height = max(13, rows_height // 6)
        self.workspace_teach_step_rows = []
        for index, step in enumerate(_WORKSPACE_TEACH_STEPS):
            label = self._label(
                guidance,
                "--  %s" % step.upper(),
                pad,
                rows_y + (index * row_height),
                self.DIM,
                self.font_small,
            )
            label.set_width(guidance_width - (pad * 2))
            self.workspace_teach_step_rows.append(label)
        self.workspace_teach_digest = self._label(
            guidance,
            "PROPOSAL SHA256 --",
            pad,
            body_height - pad - 43,
            self.DIM,
            self.font_small,
        )
        self.workspace_teach_digest.set_width(guidance_width - (pad * 2))
        self.workspace_teach_safety_notice = self._label(
            guidance,
            _WORKSPACE_TEACH_SAFETY_NOTICE,
            pad,
            body_height - pad - 20,
            self.WARN,
            self.font_small,
        )
        self.workspace_teach_safety_notice.set_width(guidance_width - (pad * 2))

        action = self._panel(
            overlay,
            canvas_x,
            top + body_height + gap,
            canvas_width,
            action_height,
            self.PANEL,
            self.BORDER,
            14,
        )
        action_pad = max(9, int(11 * min(self.scale, 1.2)))
        cancel_width = min(190, int(canvas_width * 0.20))
        primary_width = min(315, int(canvas_width * 0.34))
        button_height = max(44, action_height - (action_pad * 2))
        self.workspace_teach_action_detail = self._label(
            action,
            "Health-Snapshot ist die alleinige Zustandsquelle",
            action_pad,
            action_pad + max(4, int(5 * min(self.scale, 1.2))),
            self.MUTED,
            self.font_small,
        )
        self.workspace_teach_action_detail.set_width(
            canvas_width - primary_width - cancel_width - (action_pad * 5)
        )
        self.workspace_teach_cancel_button = self._panel(
            action,
            canvas_width - action_pad - primary_width - action_pad - cancel_width,
            action_pad,
            cancel_width,
            button_height,
            self.DIM,
            self.DIM,
            button_height // 2,
        )
        self.workspace_teach_cancel_label = self._label(
            self.workspace_teach_cancel_button,
            "SESSION VERWERFEN",
            0,
            0,
            self.INK,
            self.font_small,
        )
        self.workspace_teach_cancel_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self.workspace_teach_primary_button = self._panel(
            action,
            canvas_width - action_pad - primary_width,
            action_pad,
            primary_width,
            button_height,
            self.DIM,
            self.DIM,
            button_height // 2,
        )
        self.workspace_teach_primary_label = self._label(
            self.workspace_teach_primary_button,
            "NICHT FREIGEGEBEN",
            0,
            0,
            self.INK,
            self.font_body,
        )
        self.workspace_teach_primary_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._workspace_teach_primary_callback = self._workspace_teach_primary_click
        self._workspace_teach_cancel_callback = self._workspace_teach_cancel_click
        self._make_clickable(
            self.workspace_teach_primary_button,
            self._workspace_teach_primary_callback,
        )
        self._make_clickable(
            self.workspace_teach_cancel_button,
            self._workspace_teach_cancel_callback,
        )
        return overlay

    def _build_tenant_auth_view(self, canvas_x, canvas_width, margin):
        """Build tenant URL and mobile-login input without persisting password."""

        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        nav_height = self._build_back_header(
            overlay,
            canvas_x,
            canvas_width,
            margin,
            "SUPRATIX TENANT LOGIN",
        )
        top = margin + nav_height + max(10, int(12 * self.scale))
        gap = max(10, int(12 * min(self.scale, 1.2)))
        content_height = self.height - top - margin
        form_width = int((canvas_width - gap) * 0.48)
        keyboard_width = canvas_width - form_width - gap
        form = self._panel(
            overlay,
            canvas_x,
            top,
            form_width,
            content_height,
            self.CARD,
            self.BORDER,
            14,
        )
        keyboard_panel = self._panel(
            overlay,
            canvas_x + form_width + gap,
            top,
            keyboard_width,
            content_height,
            self.PANEL,
            self.BORDER,
            14,
        )
        pad = max(12, int(14 * min(self.scale, 1.2)))
        self.tenant_auth_headline = self._label(
            form,
            "NICHT ANGEMELDET",
            pad,
            pad,
            self.MUTED,
            self.font_body,
        )
        self.tenant_auth_headline.set_width(form_width - (pad * 2))
        self.tenant_auth_detail = self._label(
            form,
            "Tenant-Domain, Benutzername und Passwort eingeben",
            pad,
            pad + 28,
            self.MUTED,
            self.font_small,
        )
        self.tenant_auth_detail.set_width(form_width - (pad * 2))

        textarea_type = getattr(self.lv, "textarea", None)
        keyboard_type = getattr(self.lv, "keyboard", None)
        self.tenant_auth_input_supported = bool(
            callable(textarea_type) and callable(keyboard_type)
        )
        self.tenant_auth_tenant_input = None
        self.tenant_auth_username_input = None
        self.tenant_auth_password_input = None
        self.tenant_auth_keyboard = None
        field_width = form_width - (pad * 2)
        field_height = max(43, int(46 * min(self.scale, 1.15)))
        first_y = pad + 65
        field_gap = max(15, int(17 * min(self.scale, 1.15)))

        if self.tenant_auth_input_supported:
            field_specs = (
                ("tenant", "https://tenant.example", 512, False),
                ("username", "Benutzername oder E-Mail", 254, False),
                ("password", "Passwort", 128, True),
            )
            fields = {}
            for index, spec in enumerate(field_specs):
                name, placeholder, maximum, password_mode = spec
                field = textarea_type(form)
                field.set_pos(pad, first_y + index * (field_height + field_gap))
                field.set_size(field_width, field_height)
                set_one_line = getattr(field, "set_one_line", None)
                if callable(set_one_line):
                    set_one_line(True)
                set_placeholder = getattr(field, "set_placeholder_text", None)
                if callable(set_placeholder):
                    set_placeholder(placeholder)
                set_max_length = getattr(field, "set_max_length", None)
                if callable(set_max_length):
                    set_max_length(maximum)
                set_password_mode = getattr(field, "set_password_mode", None)
                if password_mode and callable(set_password_mode):
                    set_password_mode(True)
                self._disable_scroll(field)
                fields[name] = field
            self.tenant_auth_tenant_input = fields["tenant"]
            self.tenant_auth_username_input = fields["username"]
            self.tenant_auth_password_input = fields["password"]
            keyboard = keyboard_type(keyboard_panel)
            keyboard.set_pos(0, 0)
            keyboard.set_size(keyboard_width, content_height)
            self.tenant_auth_keyboard = keyboard

            def select_field(field):
                def select(_event=None):
                    setter = getattr(self.tenant_auth_keyboard, "set_textarea", None)
                    if callable(setter):
                        setter(field)

                return select

            for field in fields.values():
                self._make_clickable(field, select_field(field))
            setter = getattr(keyboard, "set_textarea", None)
            if callable(setter):
                setter(self.tenant_auth_tenant_input)
        else:
            unavailable = self._label(
                keyboard_panel,
                "PINNED LVGL TEXTAREA / KEYBOARD UNAVAILABLE",
                pad,
                max(20, content_height // 2),
                self.DANGER,
                self.font_small,
            )
            unavailable.set_width(keyboard_width - (pad * 2))
            unavailable.set_style_text_align(self.lv.TEXT_ALIGN.CENTER, 0)

        button_y = content_height - pad - max(48, field_height)
        button_gap = max(8, int(10 * min(self.scale, 1.2)))
        button_width = (field_width - button_gap) // 2
        self.tenant_auth_logout_button = self._panel(
            form,
            pad,
            button_y,
            button_width,
            field_height,
            self.DIM,
            self.DIM,
            field_height // 2,
        )
        self.tenant_auth_logout_label = self._label(
            self.tenant_auth_logout_button,
            "ABMELDEN",
            0,
            0,
            self.INK,
            self.font_small,
        )
        self.tenant_auth_logout_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self.tenant_auth_login_button = self._panel(
            form,
            pad + button_width + button_gap,
            button_y,
            field_width - button_width - button_gap,
            field_height,
            self.DIM,
            self.DIM,
            field_height // 2,
        )
        self.tenant_auth_login_label = self._label(
            self.tenant_auth_login_button,
            "ANMELDEN",
            0,
            0,
            self.INK,
            self.font_body,
        )
        self.tenant_auth_login_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._tenant_auth_login_callback = self._tenant_auth_login_click
        self._tenant_auth_logout_callback = self._tenant_auth_logout_click
        self._make_clickable(
            self.tenant_auth_login_button,
            self._tenant_auth_login_callback,
        )
        self._make_clickable(
            self.tenant_auth_logout_button,
            self._tenant_auth_logout_callback,
        )
        return overlay

    def _build_robot_metrics_view(self, canvas_x, canvas_width, margin):
        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        nav_height = max(44, int(46 * min(self.scale, 1.3)))
        back_width = max(150, int(160 * min(self.scale, 1.2)))
        back_button = self._panel(
            overlay,
            canvas_x,
            margin,
            back_width,
            nav_height,
            self.CARD,
            self.ACCENT,
            nav_height // 2,
        )
        back_label = self._label(
            back_button,
            "< ROBOT CONTROL",
            0,
            0,
            self.ACCENT,
            self.font_small,
        )
        back_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._robot_metrics_back_callback = self._show_system
        self._make_clickable(back_button, self._robot_metrics_back_callback)
        self._label(
            overlay,
            "xARM LITE6 ROBOT METRICS",
            canvas_x + back_width + max(20, int(22 * self.scale)),
            margin + max(7, int(8 * min(self.scale, 1.2))),
            self.TEXT,
            self.font_title,
        )

        badge_width = max(155, int(165 * min(self.scale, 1.2)))
        self.system_metrics_fresh_badge = self._panel(
            overlay,
            canvas_x + canvas_width - badge_width,
            margin,
            badge_width,
            nav_height,
            self.CARD,
            self.WARN,
            nav_height // 2,
        )
        self.system_metrics_fresh_label = self._label(
            self.system_metrics_fresh_badge,
            "TELEMETRY WAIT",
            0,
            0,
            self.WARN,
            self.font_small,
        )
        self.system_metrics_fresh_label.align(self.lv.ALIGN.CENTER, 0, 0)

        top = margin + nav_height + max(13, int(14 * self.scale))
        footer_height = max(54, int(58 * min(self.scale, 1.2)))
        card_height = self.height - top - footer_height - margin
        self.system_metrics_card = self._panel(
            overlay,
            canvas_x,
            top,
            canvas_width,
            card_height,
            self.CARD,
            self.BORDER,
            14,
        )
        pad = max(14, int(16 * min(self.scale, 1.2)))
        self.system_metrics_page_title = self._label(
            self.system_metrics_card,
            "STATUS",
            pad,
            pad,
            self.TEXT,
            self.font_title,
        )
        self.system_metrics_page_number = self._label(
            self.system_metrics_card,
            "PAGE 1 / 4",
            canvas_width - pad - 105,
            pad + 5,
            self.DIM,
            self.font_small,
        )
        rows_top = pad + max(38, int(42 * min(self.scale, 1.2)))
        row_gap = max(3, int(4 * min(self.scale, 1.2)))
        column_gap = max(10, int(12 * min(self.scale, 1.2)))
        column_width = (canvas_width - (pad * 2) - column_gap) // 2
        row_count = 7
        available_rows_height = max(0, card_height - rows_top - pad)
        row_height = max(
            32,
            (available_rows_height - (row_gap * (row_count - 1))) // row_count,
        )
        self.system_metrics_rows = []
        for index in range(14):
            column = index % 2
            row = index // 2
            panel = self._panel(
                self.system_metrics_card,
                pad + (column * (column_width + column_gap)),
                rows_top + (row * (row_height + row_gap)),
                column_width,
                row_height,
                self.PANEL,
                self.BORDER,
                9,
            )
            label = self._label(
                panel,
                "METRIC",
                12,
                max(3, int(4 * min(self.scale, 1.2))),
                self.DIM,
                self.font_small,
            )
            value = self._label(
                panel,
                "UNAVAILABLE",
                12,
                max(17, row_height // 2),
                self.MUTED,
                self.font_small,
            )
            value.set_width(column_width - 24)
            self.system_metrics_rows.append(
                {"panel": panel, "label": label, "value": value}
            )

        nav_y = self.height - margin - footer_height + max(7, int(8 * self.scale))
        page_button_width = max(150, int(160 * min(self.scale, 1.2)))
        page_button_height = max(42, int(44 * min(self.scale, 1.2)))
        self.system_metrics_previous_button = self._panel(
            overlay,
            canvas_x,
            nav_y,
            page_button_width,
            page_button_height,
            self.CARD,
            self.ACCENT,
            page_button_height // 2,
        )
        previous_label = self._label(
            self.system_metrics_previous_button,
            "< PREVIOUS",
            0,
            0,
            self.ACCENT,
            self.font_small,
        )
        previous_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._previous_robot_metrics_callback = self._show_previous_robot_metrics
        self._make_clickable(
            self.system_metrics_previous_button,
            self._previous_robot_metrics_callback,
        )
        self.system_metrics_next_button = self._panel(
            overlay,
            canvas_x + canvas_width - page_button_width,
            nav_y,
            page_button_width,
            page_button_height,
            self.CARD,
            self.ACCENT,
            page_button_height // 2,
        )
        next_label = self._label(
            self.system_metrics_next_button,
            "NEXT >",
            0,
            0,
            self.ACCENT,
            self.font_small,
        )
        next_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._next_robot_metrics_callback = self._show_next_robot_metrics
        self._make_clickable(
            self.system_metrics_next_button,
            self._next_robot_metrics_callback,
        )
        return overlay

    def _build_safety_config_view(self, canvas_x, canvas_width, margin):
        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        nav_height = max(44, int(46 * min(self.scale, 1.3)))
        back_width = max(150, int(160 * min(self.scale, 1.2)))
        back = self._panel(
            overlay,
            canvas_x,
            margin,
            back_width,
            nav_height,
            self.CARD,
            self.ACCENT,
            nav_height // 2,
        )
        label = self._label(back, "< ROBOT CONTROL", 0, 0, self.ACCENT, self.font_small)
        label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._make_clickable(back, self._show_system)
        self._label(
            overlay,
            "LITE6 TCP SAFETY BOUNDARY SETUP",
            canvas_x + back_width + max(18, int(20 * self.scale)),
            margin + 7,
            self.TEXT,
            self.font_title,
        )

        top = margin + nav_height + max(10, int(12 * self.scale))
        gap = max(10, int(12 * self.scale))
        footer_height = max(76, int(80 * min(self.scale, 1.2)))
        content_height = self.height - top - footer_height - margin
        left_width = int((canvas_width - gap) * 0.59)
        right_width = canvas_width - left_width - gap
        self.safety_profile_panel = self._panel(
            overlay,
            canvas_x,
            top,
            left_width,
            content_height,
            self.CARD,
            self.BORDER,
            14,
        )
        self.safety_gate_panel = self._panel(
            overlay,
            canvas_x + left_width + gap,
            top,
            right_width,
            content_height,
            self.CARD,
            self.BORDER,
            14,
        )
        pad = max(12, int(14 * min(self.scale, 1.2)))
        self.safety_headline = self._label(
            self.safety_profile_panel,
            "SAFETY-PROFIL NICHT VERFUEGBAR",
            pad,
            pad,
            self.WARN,
            self.font_body,
        )
        self.safety_detail = self._label(
            self.safety_profile_panel,
            "Backend-Profil und Controller-Readback fehlen",
            pad,
            pad + 27,
            self.MUTED,
            self.font_small,
        )
        self.safety_detail.set_width(left_width - (pad * 2))
        self.safety_digest = self._label(
            self.safety_profile_panel,
            "PROFILE SHA256: --",
            pad,
            pad + 52,
            self.DIM,
            self.font_small,
        )
        self.safety_digest.set_width(left_width - (pad * 2))
        rows_top = pad + 76
        column_gap = 7
        row_gap = 3
        columns = 2
        column_width = (left_width - (pad * 2) - column_gap) // columns
        rows_per_column = 7
        row_height = max(
            31,
            (content_height - rows_top - pad - (row_gap * (rows_per_column - 1)))
            // rows_per_column,
        )
        self.safety_profile_rows = []
        for index in range(14):
            column = index % 2
            row = index // 2
            panel = self._panel(
                self.safety_profile_panel,
                pad + column * (column_width + column_gap),
                rows_top + row * (row_height + row_gap),
                column_width,
                row_height,
                self.PANEL,
                self.BORDER,
                7,
            )
            row_label = self._label(panel, "VALUE", 8, 3, self.DIM, self.font_small)
            value = self._label(
                panel,
                "--",
                8,
                max(16, row_height // 2),
                self.MUTED,
                self.font_small,
            )
            value.set_width(column_width - 16)
            self.safety_profile_rows.append(
                {"panel": panel, "label": row_label, "value": value}
            )

        self._label(
            self.safety_gate_panel,
            "PREFLIGHT + SEARCH GATES",
            pad,
            pad,
            self.DIM,
            self.font_small,
        )
        self.safety_preflight_labels = []
        gate_y = pad + 28
        for index in range(10):
            gate = self._label(
                self.safety_gate_panel,
                "--",
                pad,
                gate_y + index * 15,
                self.MUTED,
                self.font_small,
            )
            gate.set_width(right_width - (pad * 2))
            self.safety_preflight_labels.append(gate)
        divider_y = gate_y + 154
        self._panel(
            self.safety_gate_panel,
            pad,
            divider_y,
            right_width - (pad * 2),
            1,
            self.BORDER,
            self.BORDER,
            0,
        )
        self.safety_remaining_title = self._label(
            self.safety_gate_panel,
            "VERBLEIBENDE SEARCH-GATES",
            pad,
            divider_y + 12,
            self.DIM,
            self.font_small,
        )
        self.safety_remaining_labels = []
        for index in range(12):
            gate = self._label(
                self.safety_gate_panel,
                "--",
                pad,
                divider_y + 28 + index * 13,
                self.WARN,
                self.font_small,
            )
            gate.set_width(right_width - (pad * 2))
            self.safety_remaining_labels.append(gate)

        action_y = self.height - margin - footer_height + 8
        action_height = max(48, footer_height - 12)
        action_width = min(340, int(canvas_width * 0.36))
        self.safety_config_button = self._panel(
            overlay,
            canvas_x,
            action_y,
            action_width,
            action_height,
            self.CARD,
            self.WARN,
            action_height // 2,
        )
        self.safety_config_button_label = self._label(
            self.safety_config_button,
            "NICHT VERFUEGBAR",
            0,
            0,
            self.WARN,
            self.font_body,
        )
        self.safety_config_button_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._make_clickable(
            self.safety_config_button,
            self._safety_configuration_click,
        )
        boundary_width = min(280, max(190, int(canvas_width * 0.24)))
        self.workspace_boundary_setup_button = self._panel(
            overlay,
            canvas_x + action_width + gap,
            action_y,
            boundary_width,
            action_height,
            self.CARD,
            self.ACCENT,
            action_height // 2,
        )
        self.workspace_boundary_setup_label = self._label(
            self.workspace_boundary_setup_button,
            "ARBEITSRAUM EINMESSEN",
            0,
            0,
            self.ACCENT,
            self.font_small,
        )
        self.workspace_boundary_setup_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._make_clickable(
            self.workspace_boundary_setup_button,
            self._show_workspace_teach,
        )
        stop_width = max(180, int(195 * min(self.scale, 1.2)))
        self.safety_stop_button = self._panel(
            overlay,
            canvas_x + canvas_width - stop_width,
            action_y,
            stop_width,
            action_height,
            self.CARD,
            self.DANGER,
            action_height // 2,
        )
        stop_label = self._label(
            self.safety_stop_button,
            "SOFTWARE STOP",
            0,
            0,
            self.DANGER,
            self.font_body,
        )
        stop_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._make_clickable(self.safety_stop_button, self._software_stop_click)
        return overlay

    def _build_software_stop_nav(self, canvas_x, canvas_width, margin):
        height = max(44, int(46 * min(self.scale, 1.2)))
        width = max(170, int(184 * min(self.scale, 1.2)))
        button = self._panel(
            self.screen,
            canvas_x + canvas_width - width,
            margin,
            width,
            height,
            self.DANGER,
            self.DANGER,
            height // 2,
        )
        label = self._label(
            button,
            "SOFTWARE STOP",
            0,
            0,
            self.INK,
            self.font_body,
        )
        label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._software_stop_callback = self._software_stop_click
        self._make_clickable(button, self._software_stop_callback)
        button.add_flag(self.lv.obj.FLAG.HIDDEN)
        return button

    def _build_hand_training_view(self, canvas_x, canvas_width, margin):
        """Build the simple Start / Tool / End recording page."""

        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        nav_height = self._build_back_header(
            overlay, canvas_x, canvas_width, margin, "HAND TRAINING"
        )
        top = margin + nav_height + max(18, int(20 * self.scale))
        status_card = self._panel(
            overlay,
            canvas_x,
            top,
            canvas_width,
            max(120, int(132 * min(self.scale, 1.2))),
            self.CARD,
            self.BORDER,
            16,
        )
        self.hand_training_state = self._label(
            status_card, "NOT CONFIGURED", 20, 18, self.WARN, self.font_title
        )
        self.hand_training_detail = self._label(
            status_card,
            "Start requires tenant login, both cameras and xArm Teach Mode 2.",
            20,
            54,
            self.MUTED,
            self.font_body,
        )
        self.hand_training_detail.set_width(canvas_width - 40)
        self.hand_training_progress = self._label(
            status_card, "0 SAMPLES  /  0.0 S", 20, 88, self.TEXT, self.font_small
        )

        gap = max(12, int(16 * self.scale))
        button_y = top + max(148, int(158 * min(self.scale, 1.2)))
        button_width = (canvas_width - (gap * 2)) // 3
        button_height = max(92, int(104 * min(self.scale, 1.2)))

        def action_button(x, title, subtitle, color, callback):
            button = self._panel(
                overlay,
                x,
                button_y,
                button_width,
                button_height,
                self.CARD,
                color,
                16,
            )
            label = self._label(button, title, 0, 21, color, self.font_title)
            label.set_width(button_width)
            label.set_style_text_align(self.lv.TEXT_ALIGN.CENTER, 0)
            detail = self._label(button, subtitle, 0, 59, self.MUTED, self.font_small)
            detail.set_width(button_width)
            detail.set_style_text_align(self.lv.TEXT_ALIGN.CENTER, 0)
            self._make_clickable(button, callback)
            return {"button": button, "label": label, "detail": detail}

        self._hand_training_start_callback = self._hand_training_start_click
        self._hand_training_tool_callback = self._hand_training_tool_click
        self._hand_training_end_callback = self._hand_training_end_click
        self.hand_training_start_button = action_button(
            canvas_x,
            "START",
            "BOTH CAMERAS + METRICS",
            self.OK,
            self._hand_training_start_callback,
        )
        self.hand_training_tool_button = action_button(
            canvas_x + button_width + gap,
            "TOOL ON",
            "CONFIRMED TOOL LABEL",
            self.ACCENT,
            self._hand_training_tool_callback,
        )
        self.hand_training_end_button = action_button(
            canvas_x + ((button_width + gap) * 2),
            "END RECORDING",
            "UPLOAD TO DATAHUB",
            self.DANGER,
            self._hand_training_end_callback,
        )
        note = self._label(
            overlay,
            "The app never changes xArm mode or enables motion. Position the arm by hand in Teach Mode.",
            canvas_x,
            button_y + button_height + max(20, int(24 * self.scale)),
            self.MUTED,
            self.font_small,
        )
        note.set_width(canvas_width)
        note.set_style_text_align(self.lv.TEXT_ALIGN.CENTER, 0)
        return overlay

    def _build_metrics_view(self, canvas_x, canvas_width, margin):
        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        nav_height = self._build_back_header(
            overlay, canvas_x, canvas_width, margin, "SYSTEM METRICS DASHBOARD"
        )
        top = margin + nav_height + max(18, int(20 * self.scale))
        gap = max(9, int(10 * self.scale))
        tile_width = (canvas_width - (gap * 3)) // 4
        tile_height = max(96, int(100 * min(self.scale, 1.2)))
        self.metric_tiles = {}
        metrics = (
            ("gateway", "RUNTIME", "CONNECTING"),
            ("cameras", "CAMERAS", "0 / 2 LIVE"),
            ("motion", "xARM SAFETY", "UNKNOWN"),
            ("capture", "CAPTURE", "NOT CONFIGURED"),
            ("dataset", "DATASET EXPORT", "NOT CONFIGURED"),
            ("ota", "OTA", "UNAVAILABLE"),
            ("cpu", "CPU", "UNAVAILABLE"),
            ("memory", "MEMORY", "UNAVAILABLE"),
            ("disk", "STATE DISK", "UNAVAILABLE"),
            ("network", "NETWORK + REGISTRY", "UNAVAILABLE"),
            ("workers", "SERVICES", "UNAVAILABLE"),
            ("cloud", "DATAHUB", "UNAVAILABLE"),
        )
        for index, metric in enumerate(metrics):
            key, eyebrow, initial = metric
            column = index % 4
            row = index // 4
            tile = self._panel(
                overlay,
                canvas_x + (column * (tile_width + gap)),
                top + (row * (tile_height + gap)),
                tile_width,
                tile_height,
                self.CARD,
                self.BORDER,
                14,
            )
            self._label(tile, eyebrow, 16, 14, self.DIM, self.font_small)
            value = self._label(tile, initial, 16, 45, self.TEXT, self.font_body)
            value.set_width(tile_width - 32)
            self.metric_tiles[key] = {"tile": tile, "value": value}
        operations_width = min(260, canvas_width)
        operations_height = 38
        self.metrics_operations_button = self._panel(
            overlay,
            canvas_x + (canvas_width - operations_width) // 2,
            self.height - margin - operations_height,
            operations_width,
            operations_height,
            self.ACCENT,
            self.ACCENT,
            operations_height // 2,
        )
        operations_label = self._label(
            self.metrics_operations_button,
            "OPERATIONS >",
            0,
            0,
            self.INK,
            self.font_body,
        )
        operations_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._open_operations_callback = self._show_operations
        self._make_clickable(
            self.metrics_operations_button,
            self._open_operations_callback,
        )
        return overlay

    def _build_operations_view(self, canvas_x, canvas_width, margin):
        """Build the bounded dashboard for all remaining operator workflows."""

        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        nav_height = self._build_back_header(
            overlay, canvas_x, canvas_width, margin, "AINA OPERATIONS"
        )
        top = margin + nav_height + max(10, int(12 * self.scale))
        gap = max(8, int(9 * self.scale))
        card_width = (canvas_width - (gap * 2)) // 3
        card_height = max(164, int(170 * min(self.scale, 1.1)))
        self.operation_cards = {}
        definitions = (
            ("petri", "PETRI WORKFLOW"),
            ("registration", "REGISTRATION"),
            ("datahub", "DATAHUB / OUTBOX"),
            ("recovery", "REVIEWED RECOVERY"),
            ("identity", "IDENTITY / REVIEW"),
            ("history", "HISTORY / EXPORT"),
        )
        for index, definition in enumerate(definitions):
            key, title = definition
            row = index // 3
            column = index % 3
            card = self._panel(
                overlay,
                canvas_x + column * (card_width + gap),
                top + row * (card_height + gap),
                card_width,
                card_height,
                self.CARD,
                self.BORDER,
                12,
            )
            self._label(card, title, 14, 11, self.DIM, self.font_small)
            status = self._label(card, "UNAVAILABLE", 14, 38, self.TEXT, self.font_body)
            status.set_width(card_width - 28)
            detail = self._label(card, "--", 14, 68, self.MUTED, self.font_small)
            detail.set_width(card_width - 28)
            button = None
            button_label = None
            callback = None
            if key in ("petri", "registration", "recovery", "identity"):
                button = self._panel(
                    card,
                    14,
                    card_height - 48,
                    card_width - 28,
                    36,
                    self.DIM,
                    self.DIM,
                    18,
                )
                button_label = self._label(
                    button,
                    "NICHT VERFUEGBAR",
                    0,
                    0,
                    self.INK,
                    self.font_small,
                )
                button_label.align(self.lv.ALIGN.CENTER, 0, 0)
                if key == "petri":
                    callback = self._petri_action_click
                elif key == "registration":
                    callback = self._registration_action_click
                elif key == "identity":
                    callback = self._manual_review_action_click
                else:
                    callback = self._recovery_action_click
                self._make_clickable(button, callback)
            self.operation_cards[key] = {
                "card": card,
                "status": status,
                "detail": detail,
                "button": button,
                "button_label": button_label,
                "callback": callback,
            }
        return overlay

    def _build_production_view(self, canvas_x, canvas_width, margin):
        """Build the bounded #327 production console with permanent STOP."""

        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        nav_height = self._build_back_header(
            overlay, canvas_x, canvas_width, margin, "AINA PRODUCTION"
        )
        stop_width = max(170, int(190 * min(self.scale, 1.2)))
        stop_height = max(40, int(42 * min(self.scale, 1.2)))
        self.production_stop_button = self._panel(
            overlay,
            canvas_x + canvas_width - stop_width,
            margin,
            stop_width,
            stop_height,
            self.CARD,
            self.DANGER,
            stop_height // 2,
        )
        self.production_stop_label = self._label(
            self.production_stop_button,
            "SOFTWARE STOP",
            0,
            0,
            self.DANGER,
            self.font_body,
        )
        self.production_stop_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._production_stop_callback = self._software_stop_click
        self._make_clickable(
            self.production_stop_button,
            self._production_stop_callback,
        )

        top = margin + nav_height + max(10, int(12 * self.scale))
        gap = max(8, int(9 * self.scale))
        card_width = (canvas_width - (gap * 2)) // 3
        card_height = max(164, int(170 * min(self.scale, 1.1)))
        self.production_cards = {}
        definitions = (
            ("readiness", "READ-ONLY PREFLIGHT"),
            ("workflow", "PETRI WORKFLOW"),
            ("hardware", "XARM / CAMERAS / TOOL"),
            ("datahub", "DATAHUB / OUTBOX"),
            ("recovery", "SUPERVISED RECOVERY"),
            ("ota", "OTA / UPDATE HISTORY"),
        )
        for index, definition in enumerate(definitions):
            key, title = definition
            row = index // 3
            column = index % 3
            card = self._panel(
                overlay,
                canvas_x + column * (card_width + gap),
                top + row * (card_height + gap),
                card_width,
                card_height,
                self.CARD,
                self.BORDER,
                12,
            )
            self._label(card, title, 14, 11, self.DIM, self.font_small)
            status = self._label(card, "UNAVAILABLE", 14, 38, self.TEXT, self.font_body)
            status.set_width(card_width - 28)
            detail = self._label(card, "--", 14, 68, self.MUTED, self.font_small)
            detail.set_width(card_width - 28)
            button = None
            button_label = None
            callback = None
            if key in ("workflow", "recovery", "ota"):
                button = self._panel(
                    card,
                    14,
                    card_height - 48,
                    card_width - 28,
                    36,
                    self.DIM,
                    self.DIM,
                    18,
                )
                button_label = self._label(
                    button,
                    "GESPERRT",
                    0,
                    0,
                    self.INK,
                    self.font_small,
                )
                button_label.align(self.lv.ALIGN.CENTER, 0, 0)
                callback = (
                    self._petri_action_click
                    if key == "workflow"
                    else (
                        self._recovery_action_click
                        if key == "recovery"
                        else self._show_updates
                    )
                )
                self._make_clickable(button, callback)
            self.production_cards[key] = {
                "card": card,
                "status": status,
                "detail": detail,
                "button": button,
                "button_label": button_label,
                "callback": callback,
            }
        return overlay

    def _build_manual_review_view(self, canvas_x, canvas_width, margin):
        """Build a full visual evidence page for one backend-bound candidate."""

        overlay = self._panel(
            self.screen, 0, 0, self.width, self.height, self.BG, self.BG, 0
        )
        nav_height = max(44, int(46 * min(self.scale, 1.3)))
        back_button = self._panel(
            overlay,
            canvas_x,
            margin,
            max(144, int(150 * min(self.scale, 1.2))),
            nav_height,
            self.CARD,
            self.ACCENT,
            nav_height // 2,
        )
        back_label = self._label(
            back_button, "<  OPERATIONS", 0, 0, self.ACCENT, self.font_body
        )
        back_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._manual_review_back_callback = self._show_operations
        self._make_clickable(back_button, self._manual_review_back_callback)
        self._label(
            overlay,
            "PETRI MANUAL REVIEW",
            canvas_x + max(168, int(176 * min(self.scale, 1.2))),
            margin + max(7, int(8 * min(self.scale, 1.2))),
            self.TEXT,
            self.font_title,
        )
        top = margin + nav_height + max(10, int(12 * self.scale))
        content_height = self.height - top - margin
        gap = max(10, int(12 * self.scale))
        image_width = max(360, int((canvas_width - gap) * 0.66))
        info_width = canvas_width - image_width - gap
        preview = self._panel(
            overlay,
            canvas_x,
            top,
            image_width,
            content_height,
            self.PANEL,
            self.BORDER,
            12,
        )
        self.manual_review_preview_label = self._label(
            preview,
            "VISUELLE PRUEFUNG WIRD GELADEN",
            0,
            content_height // 2 - 10,
            self.MUTED,
            self.font_body,
        )
        self.manual_review_preview_label.set_width(image_width)
        self.manual_review_preview_label.set_style_text_align(
            self.lv.TEXT_ALIGN.CENTER, 0
        )
        self.manual_review_image = self.lv.image(preview)
        self.manual_review_image.set_pos(0, 0)
        self.manual_review_image.set_size(image_width, content_height)
        self.manual_review_image.add_flag(self.lv.obj.FLAG.HIDDEN)
        self.manual_review_preview_width = image_width
        self.manual_review_preview_height = content_height

        info = self._panel(
            overlay,
            canvas_x + image_width + gap,
            top,
            info_width,
            content_height,
            self.CARD,
            self.BORDER,
            12,
        )
        self._label(info, "BACKEND-KANDIDAT", 14, 14, self.DIM, self.font_small)
        self.manual_review_candidate_label = self._label(
            info, "--", 14, 44, self.TEXT, self.font_body
        )
        self.manual_review_candidate_label.set_width(info_width - 28)
        warning = self._label(
            info,
            "Nur bestaetigen, wenn das Bild eindeutig den richtigen Petri-Bereich zeigt.",
            14,
            max(122, content_height - 132),
            self.WARN,
            self.font_small,
        )
        warning.set_width(info_width - 28)
        self.manual_review_confirm_button = self._panel(
            info,
            14,
            content_height - 54,
            info_width - 28,
            40,
            self.DIM,
            self.DIM,
            20,
        )
        self.manual_review_confirm_label = self._label(
            self.manual_review_confirm_button,
            "GESPERRT",
            0,
            0,
            self.INK,
            self.font_body,
        )
        self.manual_review_confirm_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._manual_review_confirm_callback = self._manual_review_confirm_click
        self._make_clickable(
            self.manual_review_confirm_button,
            self._manual_review_confirm_callback,
        )
        return overlay

    def _build_update_view(self, canvas_x, canvas_width, margin):
        overlay = self._panel(
            self.screen,
            0,
            0,
            self.width,
            self.height,
            self.BG,
            self.BG,
            0,
        )
        nav_height = max(36, int(38 * min(self.scale, 1.3)))
        back_button = self._panel(
            overlay,
            canvas_x,
            margin,
            108,
            nav_height,
            self.CARD,
            self.BORDER,
            nav_height // 2,
        )
        back_label = self._label(
            back_button,
            "ZURUECK",
            0,
            0,
            self.TEXT,
            self.font_small,
        )
        back_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._close_updates_callback = self._show_home
        self._make_clickable(back_button, self._close_updates_callback)

        self._label(
            overlay,
            "SYSTEM UPDATE",
            canvas_x + 130,
            margin + 1,
            self.TEXT,
            self.font_title,
        )
        signed_width = 236
        self.update_verification_badge = self._panel(
            overlay,
            canvas_x + canvas_width - signed_width,
            margin,
            signed_width,
            nav_height,
            self.DIM,
            self.DIM,
            nav_height // 2,
        )
        self.update_verification_label = self._label(
            self.update_verification_badge,
            "OTA STATUS",
            0,
            0,
            self.INK,
            self.font_small,
        )
        self.update_verification_label.align(self.lv.ALIGN.CENTER, 0, 0)

        card_width = min(canvas_width, max(620, int(700 * self.scale)))
        card_x = (self.width - card_width) // 2
        card_y = margin + nav_height + max(16, int(18 * self.scale))
        card_height = self.height - card_y - max(54, int(58 * self.scale))
        card = self._panel(
            overlay,
            card_x,
            card_y,
            card_width,
            card_height,
            self.CARD,
            self.BORDER,
            16,
        )
        pad = max(18, int(22 * min(self.scale, 1.4)))
        self.update_rail = self._panel(
            card,
            0,
            pad,
            6,
            card_height - (pad * 2),
            self.DIM,
            self.DIM,
            3,
        )
        self._label(
            card,
            "SECURE UPDATE STATUS",
            pad,
            pad,
            self.DIM,
            self.font_small,
        )
        self.update_headline = self._label(
            card,
            "UPDATE NICHT VERFUEGBAR",
            pad,
            pad + 30,
            self.TEXT,
            self.font_title,
        )
        self.update_detail = self._label(
            card,
            "Waiting for signed OTA status",
            pad,
            pad + 67,
            self.MUTED,
            self.font_body,
        )

        version_y = pad + 108
        version_gap = 12
        version_width = (card_width - (pad * 2) - version_gap) // 2
        current_panel = self._panel(
            card,
            pad,
            version_y,
            version_width,
            70,
            self.PANEL,
            self.BORDER,
            10,
        )
        self._label(
            current_panel,
            "INSTALLIERTE VERSION",
            12,
            10,
            self.DIM,
            self.font_small,
        )
        self.update_current_version = self._label(
            current_panel,
            "--",
            12,
            38,
            self.TEXT,
            self.font_body,
        )
        available_panel = self._panel(
            card,
            pad + version_width + version_gap,
            version_y,
            version_width,
            70,
            self.PANEL,
            self.BORDER,
            10,
        )
        self._label(
            available_panel,
            "GEFUNDENE VERSION",
            12,
            10,
            self.DIM,
            self.font_small,
        )
        self.update_available_version = self._label(
            available_panel,
            "--",
            12,
            38,
            self.TEXT,
            self.font_body,
        )

        button_width = min(280, card_width - (pad * 2))
        button_height = 48
        self.update_button = self._panel(
            card,
            (card_width - button_width) // 2,
            card_height - pad - button_height,
            button_width,
            button_height,
            self.DIM,
            self.DIM,
            button_height // 2,
        )
        self.update_button_label = self._label(
            self.update_button,
            "NICHT VERFUEGBAR",
            0,
            0,
            self.INK,
            self.font_body,
        )
        self.update_button_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._request_update_callback = self._request_update_click
        self._make_clickable(self.update_button, self._request_update_callback)

        footer = self._label(
            overlay,
            "Nur signierte Releases werden installiert - Rollback bleibt aktiv",
            canvas_x,
            self.height - max(34, int(38 * self.scale)),
            self.MUTED,
            self.font_small,
        )
        footer.set_width(canvas_width)
        footer.set_style_text_align(self.lv.TEXT_ALIGN.CENTER, 0)
        return overlay

    def _build_capture_view(self, canvas_x, canvas_width, margin):
        overlay = self._panel(
            self.screen,
            0,
            0,
            self.width,
            self.height,
            self.BG,
            self.BG,
            0,
        )
        nav_height = max(36, int(38 * min(self.scale, 1.3)))
        back_button = self._panel(
            overlay,
            canvas_x,
            margin,
            108,
            nav_height,
            self.CARD,
            self.BORDER,
            nav_height // 2,
        )
        back_label = self._label(
            back_button,
            "ZURUECK",
            0,
            0,
            self.TEXT,
            self.font_small,
        )
        back_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._close_capture_callback = self._show_home
        self._make_clickable(back_button, self._close_capture_callback)

        self._label(
            overlay,
            "CAPTURE DATASET",
            canvas_x + 130,
            margin + 1,
            self.TEXT,
            self.font_title,
        )
        badge_width = 126
        badge = self._panel(
            overlay,
            canvas_x + canvas_width - badge_width,
            margin,
            badge_width,
            nav_height,
            self.ACCENT,
            self.ACCENT,
            nav_height // 2,
        )
        badge_label = self._label(
            badge,
            "15 S / 1 HZ",
            0,
            0,
            self.INK,
            self.font_small,
        )
        badge_label.align(self.lv.ALIGN.CENTER, 0, 0)

        card_width = min(canvas_width, max(620, int(700 * self.scale)))
        card_x = (self.width - card_width) // 2
        card_y = margin + nav_height + max(16, int(18 * self.scale))
        card_height = self.height - card_y - max(54, int(58 * self.scale))
        card = self._panel(
            overlay,
            card_x,
            card_y,
            card_width,
            card_height,
            self.CARD,
            self.BORDER,
            16,
        )
        pad = max(18, int(22 * min(self.scale, 1.4)))
        self.capture_rail = self._panel(
            card,
            0,
            pad,
            6,
            card_height - (pad * 2),
            self.DIM,
            self.DIM,
            3,
        )
        self._label(
            card,
            "HARDENED MOTION + DUAL OAK DATASET",
            pad,
            pad,
            self.DIM,
            self.font_small,
        )
        self.capture_headline = self._label(
            card,
            "LAUF NICHT FREIGEGEBEN",
            pad,
            pad + 30,
            self.TEXT,
            self.font_title,
        )
        self.capture_detail = self._label(
            card,
            "Waiting for commissioned capture status",
            pad,
            pad + 67,
            self.MUTED,
            self.font_body,
        )

        progress_y = pad + 104
        self.capture_progress_width = card_width - (pad * 2)
        self.capture_progress_track = self._panel(
            card,
            pad,
            progress_y,
            self.capture_progress_width,
            14,
            self.PANEL,
            self.BORDER,
            7,
        )
        self.capture_progress_fill = self._panel(
            self.capture_progress_track,
            0,
            0,
            1,
            14,
            self.DIM,
            self.DIM,
            7,
        )
        self.capture_progress_text = self._label(
            card,
            "0 / 15 ZEITPUNKTE",
            pad,
            progress_y + 20,
            self.MUTED,
            self.font_small,
        )
        self.capture_run_id = self._label(
            card,
            "RUN --",
            card_width - pad - 250,
            progress_y + 20,
            self.DIM,
            self.font_small,
        )
        self.capture_run_id.set_width(250)
        self.capture_run_id.set_style_text_align(self.lv.TEXT_ALIGN.RIGHT, 0)

        metric_y = progress_y + 48
        metric_gap = 10
        metric_width = (card_width - (pad * 2) - metric_gap) // 2
        tool_panel = self._panel(
            card,
            pad,
            metric_y,
            metric_width,
            64,
            self.PANEL,
            self.BORDER,
            10,
        )
        self._label(
            tool_panel,
            "TOOL OAK-D LITE",
            12,
            9,
            self.DIM,
            self.font_small,
        )
        self.capture_tool_saved = self._label(
            tool_panel,
            "0 / 15 GESPEICHERT",
            12,
            35,
            self.TEXT,
            self.font_body,
        )
        workspace_panel = self._panel(
            card,
            pad + metric_width + metric_gap,
            metric_y,
            metric_width,
            64,
            self.PANEL,
            self.BORDER,
            10,
        )
        self._label(
            workspace_panel,
            "WORKSPACE OAK-D LITE",
            12,
            9,
            self.DIM,
            self.font_small,
        )
        self.capture_workspace_saved = self._label(
            workspace_panel,
            "0 / 15 GESPEICHERT",
            12,
            35,
            self.TEXT,
            self.font_body,
        )

        self.capture_dataset_sync = self._label(
            card,
            "DATASET: SENDUNG NICHT BESTAETIGT",
            pad,
            metric_y + 76,
            self.WARN,
            self.font_small,
        )
        self.capture_dataset_sync.set_width(card_width - (pad * 2))
        self.capture_dataset_sync.set_style_text_align(
            self.lv.TEXT_ALIGN.CENTER,
            0,
        )
        self.capture_evidence = self._label(
            card,
            "LOCAL MANIFEST UNAVAILABLE | ERR --",
            pad,
            metric_y + 102,
            self.MUTED,
            self.font_small,
        )
        self.capture_evidence.set_width(card_width - (pad * 2))
        self.capture_evidence.set_style_text_align(
            self.lv.TEXT_ALIGN.CENTER,
            0,
        )

        button_width = min(300, card_width - (pad * 2))
        button_height = 46
        self.capture_button = self._panel(
            card,
            (card_width - button_width) // 2,
            card_height - pad - button_height,
            button_width,
            button_height,
            self.DIM,
            self.DIM,
            button_height // 2,
        )
        self.capture_button_label = self._label(
            self.capture_button,
            "NICHT FREIGEGEBEN",
            0,
            0,
            self.INK,
            self.font_body,
        )
        self.capture_button_label.align(self.lv.ALIGN.CENTER, 0, 0)
        self._capture_action_callback = self._capture_action_click
        self._make_clickable(
            self.capture_button,
            self._capture_action_callback,
        )

        footer = self._label(
            overlay,
            "Bewegung nur mit gehashtem Pfad, zweifacher Bestaetigung und STOP",
            canvas_x,
            self.height - max(34, int(38 * self.scale)),
            self.MUTED,
            self.font_small,
        )
        footer.set_width(canvas_width)
        footer.set_style_text_align(self.lv.TEXT_ALIGN.CENTER, 0)
        return overlay

    def _activate_view(self, name, invalidate=True):
        previous_name = getattr(self, "_active_view", "")
        if name not in (
            "home",
            "tool",
            "workspace",
            "system",
            "robot_metrics",
            "safety_config",
            "capture",
            "updates",
            "metrics",
            "operations",
            "production",
            "manual_review",
            "digital_twin",
            "workspace_teach",
            "tenant_auth",
            "hand_training",
        ):
            name = "home"
        # Once physical capture has been admitted, navigation may not hide the
        # operator's immediate software STOP control.  This is intentionally
        # based on the sanitized capture reducer rather than raw backend data.
        if name != "capture" and (
            getattr(self, "_motion_stop_latched", False)
            or _capture_requires_visible_stop(self._last_view)
        ):
            origin = getattr(self, "_motion_stop_origin", "")
            name = (
                (
                    "digital_twin"
                    if name == "digital_twin"
                    or getattr(self, "_active_view", "") == "digital_twin"
                    else "system"
                )
                if origin == "search"
                else origin if origin in ("operations", "production") else "capture"
            )
        if (
            previous_name in ("operations", "production")
            and name != previous_name
            and not getattr(self, "_motion_stop_latched", False)
        ):
            if (
                getattr(self, "_operations_request_pending", False)
                or getattr(self, "_petri_start_challenge", "")
                or getattr(self, "_recovery_start_challenge", "")
            ):
                self._begin_action()
            validity = getattr(self, "_challenge_validity", None)
            if isinstance(validity, dict):
                validity.pop("_petri_start_challenge", None)
                validity.pop("_recovery_start_challenge", None)
            self._petri_start_challenge = ""
            self._recovery_start_challenge = ""
        if previous_name == "tenant_auth" and name != "tenant_auth":
            self._clear_tenant_password(
                getattr(self, "tenant_auth_password_input", None)
            )
        self._active_view = name
        for key, overlay in self._overlays.items():
            if key == name:
                overlay.remove_flag(self.lv.obj.FLAG.HIDDEN)
            else:
                overlay.add_flag(self.lv.obj.FLAG.HIDDEN)
        if invalidate:
            self.screen.invalidate()

    def _show_home(self, _event=None):
        self._activate_view("home")

    def _show_tool_stream(self, _event=None):
        self._activate_view("tool")

    def _show_workspace_stream(self, _event=None):
        self._activate_view("workspace")

    def _show_system(self, _event=None):
        # Navigation only: opening the dedicated page cannot arm, enable,
        # clear, jog, or move the robot.
        self._activate_view("system")

    def _show_digital_twin(self, _event=None):
        # Navigation only. The view consumes the existing sanitized health
        # document and cannot query cameras, select a target, or move the arm.
        self._activate_view("digital_twin")

    def _show_workspace_teach(self, _event=None):
        # Navigation only. Opening this page submits no request and cannot
        # change controller mode, motor state, coordinates, or safety bounds.
        self._activate_view("workspace_teach")

    def _show_tenant_auth(self, _event=None):
        # Navigation never submits credentials. Password entry is cleared
        # immediately after the explicit login tap.
        self._activate_view("tenant_auth")

    def _show_hand_training(self, _event=None):
        # Navigation is passive; recording begins only after the Start tap.
        self._activate_view("hand_training")

    def _select_twin_projection(self, projection, event=None):
        if not self._clicked(event) or projection not in (
            "isometric",
            "top",
            "front",
        ):
            return
        self._twin_projection = projection
        self._apply_digital_twin(getattr(self, "_last_view", {}))
        screen = getattr(self, "screen", None)
        if screen is not None:
            screen.invalidate()

    def _show_robot_metrics(self, _event=None):
        self._activate_view("robot_metrics")

    def _show_previous_robot_metrics(self, _event=None):
        if not self._clicked(_event):
            return
        self._robot_metrics_page_index = (
            int(getattr(self, "_robot_metrics_page_index", 0)) - 1
        ) % 4
        self._apply_robot_metrics(self._last_view)
        screen = getattr(self, "screen", None)
        if screen is not None:
            screen.invalidate()

    def _show_next_robot_metrics(self, _event=None):
        if not self._clicked(_event):
            return
        self._robot_metrics_page_index = (
            int(getattr(self, "_robot_metrics_page_index", 0)) + 1
        ) % 4
        self._apply_robot_metrics(self._last_view)
        screen = getattr(self, "screen", None)
        if screen is not None:
            screen.invalidate()

    def _show_system_run(self, _event=None):
        # Backward-compatible callback name: it now invokes only the reviewed
        # camera-guided search seam and accepts no free-form robot command.
        self._system_primary_click(_event)

    def _system_primary_click(self, _event=None):
        if not self._clicked(_event):
            return
        # Frontend-owned safety state outranks a later stale/offline health
        # sample. The existing Search flow consumes the one-use confirmation
        # or redirects a latched action to universal SOFTWARE STOP before it
        # can perform any new admission request.
        if getattr(self, "_motion_stop_latched", False) or getattr(
            self, "_motion_search_challenge", ""
        ):
            self._motion_search_click(_event)
            return
        control = _system_control_view(self._last_view)
        if control.get("safety_setup_required") is True:
            self._activate_view("safety_config")
            return
        if (
            getattr(self, "_active_view", "") == "digital_twin"
            and not getattr(self, "_motion_search_challenge", "")
            and not getattr(self, "_motion_stop_latched", False)
        ):
            twin = _mapping(_mapping(self._last_view).get("digital_twin"))
            if (
                twin.get("valid") is not True
                or not getattr(self, "twin_line_supported", False)
                or (
                    twin.get("preflight_ready") is not True
                    and twin.get("admission_ready") is not True
                )
            ):
                return
        if (
            control.get("search_action_allowed") is not True
            and control.get("search_request_allowed") is not True
        ):
            return
        self._motion_search_click(_event)

    def _show_updates(self, _event=None):
        self._activate_view("updates")

    def _show_capture(self, _event=None):
        self._activate_view("capture")

    def _show_metrics(self, _event=None):
        self._activate_view("metrics")

    def _show_operations(self, _event=None):
        self._activate_view("operations")

    def _show_production(self, _event=None):
        self._activate_view("production")

    def _petri_action_click(self, _event=None):
        current = _mapping(self._last_operations_view.get("petri"))
        if current.get("stop_allowed") is True:
            self._software_stop_click(_event)
            return
        self._start_async_flow(
            "operations",
            self._operator_confirmation_flow("petri", _event),
        )

    def _recovery_action_click(self, _event=None):
        current = _mapping(self._last_operations_view.get("recovery"))
        if current.get("stop_allowed") is True:
            self._software_stop_click(_event)
            return
        self._start_async_flow(
            "operations",
            self._operator_confirmation_flow("recovery", _event),
        )

    def _operator_confirmation_flow(self, operation, event):
        """Run one fixed two-touch workflow without accepting parameters."""

        if not self._clicked(event) or self._operations_request_pending:
            return
        if operation not in ("petri", "recovery"):
            return
        current = _mapping(self._last_operations_view.get(operation))
        challenge_name = (
            "_petri_start_challenge"
            if operation == "petri"
            else "_recovery_start_challenge"
        )
        challenge = getattr(self, challenge_name, "")
        if challenge:
            challenge, _record = self._challenge_for_rebuild(
                challenge_name,
                _monotonic_ms(),
            )
            if not challenge:
                setattr(self, challenge_name, "")
        second_confirmation = _lower_hex(challenge, 32)
        active_view = getattr(self, "_active_view", "operations")
        if (
            operation == "petri"
            and active_view == "production"
            and not second_confirmation
            and _mapping(
                _production_view(
                    getattr(self, "_last_view", {}),
                    getattr(self, "_last_operations_view", {}),
                ).get("petri")
            ).get("start_allowed")
            is not True
        ):
            return
        if not second_confirmation and current.get("action_allowed") is not True:
            return
        control_origin = "production" if active_view == "production" else "operations"
        if second_confirmation:
            setattr(self, challenge_name, "")
            self._motion_stop_latched = True
            self._motion_stop_origin = control_origin
        action_epoch = self._begin_action()
        self._operations_request_pending = True
        optimistic = dict(current)
        optimistic.update(
            {
                "action_allowed": False,
                "stop_allowed": bool(second_confirmation),
                "state": "starting" if second_confirmation else "confirming",
                "tone": "danger" if second_confirmation else "warn",
                "button": "SOFTWARE STOP" if second_confirmation else "BITTE WARTEN",
                "message": (
                    "Startstatus unbekannt; STOP bleibt aktiv"
                    if second_confirmation
                    else "Backend-Safety-Check laeuft"
                ),
            }
        )
        updated = dict(self._last_operations_view)
        updated[operation] = optimistic
        updated["stop_allowed"] = bool(second_confirmation)
        self._last_operations_view = updated
        self._apply_operations(updated)
        self._apply_production(getattr(self, "_last_view", {}), updated)
        self._apply_software_stop_nav(self._last_capture_view)

        requester = (
            request_petri_start if operation == "petri" else request_reviewed_recovery
        )
        response = yield requester(
            self.config["health_url"],
            challenge=challenge if second_confirmation else None,
            timeout_ms=self.config["timeout_ms"],
        )
        if action_epoch != int(getattr(self, "_action_epoch", 0)) or (
            not second_confirmation and getattr(self, "_active_view", "") != active_view
        ):
            setattr(self, challenge_name, "")
            self._operations_request_pending = False
            self._apply_production(
                getattr(self, "_last_view", {}),
                getattr(self, "_last_operations_view", {}),
            )
            return
        response = _mapping(response)
        payload = _mapping(response.get("payload"))
        try:
            status_code = int(response.get("http_status") or 0)
        except (TypeError, ValueError):
            status_code = 0
        outcome = _safe_text(payload.get("status") or "error", 24)
        result = dict(optimistic)
        if status_code == 202 and outcome == "confirm" and not second_confirmation:
            token = payload.get("challenge")
            expires = payload.get("expires_in_seconds")
            if (
                _lower_hex(token, 32)
                and isinstance(expires, int)
                and not isinstance(expires, bool)
                and 1 <= expires <= 5
                and self._remember_challenge(
                    challenge_name,
                    token,
                    expires,
                    (
                        operation,
                        action_epoch,
                        self._operator_ui_context(self._last_operations_view),
                    ),
                )
            ):
                result.update(
                    {
                        "state": "confirming",
                        "tone": "warn",
                        "action_allowed": True,
                        "stop_allowed": False,
                        "button": "NOCHMAL BESTAETIGEN",
                        "message": "Arbeitsraum frei und physischer Not-Aus erreichbar?",
                    }
                )
            else:
                result.update(
                    {
                        "state": "error",
                        "tone": "danger",
                        "action_allowed": False,
                        "stop_allowed": False,
                        "button": "GESPERRT",
                        "message": "Bestaetigungsvertrag ungueltig",
                    }
                )
        elif status_code == 202 and outcome == "accepted":
            self._motion_stop_latched = True
            self._motion_stop_origin = control_origin
            result.update(
                {
                    "state": "starting",
                    "tone": "danger",
                    "action_allowed": False,
                    "stop_allowed": True,
                    "button": "SOFTWARE STOP",
                    "message": "Kommissionierter Ablauf startet; STOP ist bereit",
                }
            )
        elif second_confirmation:
            # Admission may have succeeded even if the local response was
            # lost.  Never hide STOP after crossing that boundary.
            self._motion_stop_latched = True
            self._motion_stop_origin = control_origin
            result.update(
                {
                    "state": "starting",
                    "tone": "danger",
                    "action_allowed": False,
                    "stop_allowed": True,
                    "button": "SOFTWARE STOP",
                    "message": "Startstatus unbekannt; STOP wiederholbar",
                }
            )
        else:
            setattr(self, challenge_name, "")
            result.update(
                {
                    "state": "error" if outcome == "error" else "unavailable",
                    "tone": "danger" if outcome == "error" else "warn",
                    "action_allowed": False,
                    "stop_allowed": False,
                    "button": "GESPERRT",
                    "message": "Backend-Gate: %s"
                    % (outcome.upper() if status_code else "NO RESPONSE"),
                }
            )
        updated = dict(self._last_operations_view)
        updated[operation] = result
        updated["stop_allowed"] = bool(
            _mapping(updated.get("petri")).get("stop_allowed") is True
            or _mapping(updated.get("recovery")).get("stop_allowed") is True
        )
        self._last_operations_view = updated
        self._operations_request_pending = False
        self._apply_operations(updated)
        self._apply_production(getattr(self, "_last_view", {}), updated)
        self._apply_software_stop_nav(self._last_capture_view)
        self.screen.invalidate()

    def _registration_action_click(self, event=None):
        self._start_async_flow(
            "operations",
            self._registration_verification_flow(event),
        )

    def _registration_verification_flow(self, event=None):
        if not self._clicked(event) or self._operations_request_pending:
            return
        current = _mapping(self._last_operations_view.get("registration"))
        if current.get("action_allowed") is not True:
            return
        self._begin_action()
        self._operations_request_pending = True
        optimistic = dict(current)
        optimistic.update(
            {"status": "CHECKING", "tone": "warn", "action_allowed": False}
        )
        updated = dict(self._last_operations_view)
        updated["registration"] = optimistic
        self._last_operations_view = updated
        self._apply_operations(updated)

        response = yield request_registration_verification(
            self.config["health_url"],
            timeout_ms=self.config["timeout_ms"],
        )
        response = _mapping(response)
        payload = _mapping(response.get("payload"))
        try:
            status_code = int(response.get("http_status") or 0)
        except (TypeError, ValueError):
            status_code = 0
        outcome = _safe_text(payload.get("status") or "error", 24)
        result = dict(optimistic)
        result.update(
            {
                "ready": outcome == "verified",
                "status": outcome.upper() if status_code else "NO RESPONSE",
                "tone": (
                    "ok"
                    if outcome == "verified"
                    else "danger" if outcome == "error" or not status_code else "warn"
                ),
                "action_allowed": True,
            }
        )
        updated = dict(self._last_operations_view)
        updated["registration"] = result
        self._last_operations_view = updated
        self._operations_request_pending = False
        self._apply_operations(updated)
        self.screen.invalidate()

    def _manual_review_action_click(self, event=None):
        if (
            self._clicked(event)
            and _lower_hex(getattr(self, "_manual_review_challenge", ""), 32)
            and getattr(self, "_manual_review_preview_ready", False)
        ):
            # The card opens the visual evidence.  Acceptance is available
            # only on that dedicated page, never as a blind second card tap.
            self._activate_view("manual_review")
            return
        self._start_async_flow(
            "operations",
            self._manual_review_flow(event),
        )

    def _manual_review_confirm_click(self, event=None):
        self._start_async_flow(
            "operations",
            self._manual_review_flow(event),
        )

    def _manual_review_flow(self, event=None):
        """Approve only the backend-selected pending observation twice."""

        if not self._clicked(event) or self._operations_request_pending:
            return
        current = _mapping(self._last_operations_view.get("review"))
        challenge = getattr(self, "_manual_review_challenge", "")
        second_confirmation = bool(
            _lower_hex(challenge, 32)
            and getattr(self, "_manual_review_preview_ready", False)
        )
        if _lower_hex(challenge, 32) and not second_confirmation:
            # A candidate must never be accepted blind.  Only the validated
            # preview fetched for this exact backend challenge unlocks step 2.
            self._manual_review_challenge = ""
            self._manual_review_candidate = {}
            self._clear_manual_review_preview_source()
            return
        if not second_confirmation and current.get("action_allowed") is not True:
            return
        if not second_confirmation:
            self._manual_review_preview_ready = False
            self._clear_manual_review_preview_source()
        if second_confirmation:
            self._manual_review_challenge = ""
        self._begin_action()
        self._operations_request_pending = True
        optimistic = dict(current)
        optimistic.update(
            {
                "state": "SELECTING" if second_confirmation else "CHECKING",
                "action_allowed": False,
            }
        )
        updated = dict(self._last_operations_view)
        updated["review"] = optimistic
        self._last_operations_view = updated
        self._apply_operations(updated)

        response = yield request_manual_review(
            self.config["health_url"],
            challenge=challenge if second_confirmation else None,
            timeout_ms=self.config["timeout_ms"],
        )
        response = _mapping(response)
        payload = _mapping(response.get("payload"))
        if (
            not second_confirmation
            and int(response.get("http_status") or 0) == 202
            and payload.get("status") == "confirm"
        ):
            preview = yield fetch_manual_review_preview(
                self.config["health_url"],
                timeout_ms=self.config["timeout_ms"],
            )
            response = dict(response)
            response["preview"] = preview
        try:
            status_code = int(response.get("http_status") or 0)
        except (TypeError, ValueError):
            status_code = 0
        outcome = _safe_text(payload.get("status") or "error", 24)
        result = dict(optimistic)
        if status_code == 202 and outcome == "confirm" and not second_confirmation:
            token = payload.get("challenge")
            candidate = payload.get("candidate")
            preview = _mapping(response.get("preview"))
            jpeg = preview.get("jpeg")
            if (
                _lower_hex(token, 32)
                and _valid_manual_review_candidate(candidate)
                and int(preview.get("http_status") or 0) == 200
                and _baseline_jpeg(jpeg)
            ):
                self._manual_review_candidate = dict(candidate)
                self._manual_review_preview_ready = True
                self._manual_review_preview_bytes = jpeg
                if self._remember_challenge(
                    "_manual_review_challenge",
                    token,
                    payload.get("expires_in_seconds"),
                    (
                        "manual-review",
                        int(getattr(self, "_action_epoch", 0)),
                        candidate.get("observation_id"),
                    ),
                ):
                    result.update(
                        {
                            "state": "CONFIRMING",
                            "action_allowed": True,
                        }
                    )
                    self._apply_manual_review_preview_jpeg(jpeg)
                    self._activate_view("manual_review", invalidate=False)
                else:
                    self._manual_review_candidate = {}
                    self._manual_review_preview_ready = False
                    self._clear_manual_review_preview_source()
                    result.update(
                        {
                            "state": "PREVIEW ERROR",
                            "action_allowed": current.get("configured") is True,
                        }
                    )
            else:
                self._manual_review_challenge = ""
                self._manual_review_candidate = {}
                self._manual_review_preview_ready = False
                self._clear_manual_review_preview_source()
                result.update(
                    {
                        "state": "PREVIEW ERROR",
                        "action_allowed": current.get("configured") is True,
                    }
                )
        elif status_code == 202 and outcome == "accepted" and second_confirmation:
            accepted_id = payload.get("observation_id")
            expected_id = _mapping(getattr(self, "_manual_review_candidate", {})).get(
                "observation_id"
            )
            self._manual_review_candidate = {}
            self._manual_review_preview_ready = False
            self._clear_manual_review_preview_source()
            if accepted_id == expected_id and _safe_registry_id(accepted_id):
                result.update(
                    {
                        "state": "ACCEPTED",
                        "pending": max(0, int(current.get("pending") or 0) - 1),
                        "action_allowed": False,
                    }
                )
                self._activate_view("operations", invalidate=False)
            else:
                result.update({"state": "ERROR", "action_allowed": False})
        else:
            self._manual_review_challenge = ""
            self._manual_review_candidate = {}
            self._manual_review_preview_ready = False
            self._clear_manual_review_preview_source()
            result.update(
                {
                    "state": outcome.upper() if status_code else "NO RESPONSE",
                    "action_allowed": current.get("configured") is True,
                }
            )
        updated = dict(self._last_operations_view)
        updated["review"] = result
        self._last_operations_view = updated
        self._operations_request_pending = False
        self._apply_operations(updated)
        self.screen.invalidate()

    def _show_status(self, _event=None):
        # Backward-compatible alias for older callbacks/tests.
        self._show_system(_event)

    def _clicked(self, event):
        if event is None:
            return False
        get_code = getattr(event, "get_code", None)
        if not callable(get_code):
            return False
        try:
            return get_code() == self.lv.EVENT.CLICKED
        except Exception:
            return False

    def _record_interaction(self, now_ms=None):
        self._last_interaction_ms = _monotonic_ms() if now_ms is None else int(now_ms)

    def _touch_activity(self, event=None):
        """Record only closed-vocabulary indev activity, never an action."""

        get_code = getattr(event, "get_code", None)
        if not callable(get_code):
            return False
        try:
            code = get_code()
        except Exception:
            return False
        event_type = getattr(self.lv, "EVENT", None)
        pressed_event = getattr(event_type, "PRESSED", None)
        released_event = getattr(event_type, "RELEASED", None)
        if code != pressed_event and code != released_event:
            return False

        now = _monotonic_ms()
        self._last_input_activity_ms = now
        self._input_activity_event_count = min(
            int(getattr(self, "_input_activity_event_count", 0)) + 1,
            MAX_INPUT_ACTIVITY_COUNT,
        )
        if code == pressed_event:
            if (
                getattr(self, "_input_uncertain_contact", False)
                and getattr(self, "_input_uncertain_press_seen", False)
                and getattr(self, "_input_uncertain_release_seen", False)
            ):
                # The preceding uncertain contact completed on non-clickable
                # content.  This is a new, observed press generation.
                self._clear_uncertain_input_contact()
            self._input_uncertain_press_seen = bool(
                getattr(self, "_input_uncertain_contact", False)
            )
            self._input_activity_pressed = True
        else:
            self._input_activity_pressed = False
            if getattr(self, "_input_uncertain_contact", False):
                self._input_uncertain_release_seen = True

        # A press or release on the already-visible UI counts as activity even
        # on empty/non-action content. While asleep, only the opaque overlay's
        # CLICKED event wakes the display, preventing release-through.
        if not getattr(self, "_screensaver_active", False):
            self._record_interaction(now_ms=now)
        return True

    def _screensaver_visibility_reasons(self):
        """Return bounded no-sleep reasons derived from current UI evidence."""

        reasons = []

        def add(reason):
            if reason not in reasons and len(reasons) < 32:
                reasons.append(reason)

        if not getattr(self, "_screensaver_capability_enabled", True):
            add("input_monitor_unavailable")
        if getattr(self, "_motion_stop_latched", False):
            add("stop_latched")
        if getattr(self, "_screensaver_metrics_alarm", True):
            add("metric_danger")
        pending_reasons = (
            ("_update_request_pending", "ota_request_pending"),
            ("_capture_request_pending", "capture_request_pending"),
            ("_motion_search_request_pending", "search_request_pending"),
            ("_safety_configuration_request_pending", "safety_request_pending"),
            ("_safety_configuration_local_pending", "safety_apply_pending"),
            ("_operations_request_pending", "operation_request_pending"),
            ("_workspace_teach_request_pending", "workspace_teach_request_pending"),
            ("_software_stop_request_pending", "software_stop_pending"),
        )
        for attribute, reason in pending_reasons:
            if getattr(self, attribute, False):
                add(reason)
        challenge_reasons = (
            ("_capture_start_challenge", "capture_confirmation_pending"),
            ("_motion_search_challenge", "search_confirmation_pending"),
            ("_safety_configuration_challenge", "safety_confirmation_pending"),
            ("_petri_start_challenge", "petri_confirmation_pending"),
            ("_recovery_start_challenge", "recovery_confirmation_pending"),
            ("_manual_review_challenge", "manual_review_confirmation_pending"),
            (
                "_workspace_teach_finalize_challenge",
                "workspace_teach_finalize_pending",
            ),
        )
        for attribute, reason in challenge_reasons:
            if bool(getattr(self, attribute, "")):
                add(reason)
        if getattr(self, "_manual_review_preview_ready", False) or bool(
            getattr(self, "_manual_review_candidate", {})
        ):
            add("manual_review_preview_pending")

        view = _mapping(getattr(self, "_last_view", {}))
        if not view or view.get("health_authoritative") is not True:
            add("health_unavailable")
        elif view.get("ready") is not True:
            add("health_degraded")
        if (
            _capture_requires_visible_stop(view)
            or _search_requires_visible_stop(view)
            or _operations_require_visible_stop(view)
        ):
            add("physical_stop_required")

        ota = _mapping(getattr(self, "_last_ota_view", view.get("ota")))
        capture = _mapping(getattr(self, "_last_capture_view", view.get("capture")))
        search = _mapping(
            getattr(self, "_last_motion_search_view", view.get("motion_search"))
        )
        safety = _mapping(getattr(self, "_last_safety_configuration_view", {}))
        operations = _mapping(getattr(self, "_last_operations_view", {}))
        cameras = _mapping(view.get("cameras"))
        motion = _mapping(view.get("motion"))
        xarm = _mapping(view.get("xarm"))
        digital_twin = _mapping(view.get("digital_twin"))
        workspace_teach = _mapping(
            getattr(self, "_last_workspace_teach_view", view.get("workspace_teach"))
        )
        workspace_boundary = _mapping(view.get("workspace_boundary"))

        if ota.get("status") in ("checking", "busy", "pending_restart"):
            add("ota_active")
        if ota.get("status") == "error" or ota.get("verification_tone") == "danger":
            add("ota_verification_alarm")
        if (
            capture.get("state")
            in (
                "confirming",
                "starting",
                "running",
                "stopping",
                "fault_locked",
            )
            or capture.get("active") is True
        ):
            add("capture_boundary")
        if search.get("state") in (
            "confirming",
            "starting",
            "armed_live",
            "busy",
        ) or search.get("request_result") in ("checking", "confirm", "accepted"):
            add("search_boundary")
        if motion.get("armed") is True or motion.get("live") is True:
            add("motion_authorized")
        if motion.get("tone") in ("warn", "danger"):
            add("motion_safety_degraded")
        if xarm.get("moving") is True:
            add("xarm_moving")
        if xarm.get("valid") is False or (
            xarm.get("configured") is True
            and (
                xarm.get("connected") is not True
                or xarm.get("healthy") is not True
                or xarm.get("fresh") is not True
                or xarm.get("error_code") not in (None, 0)
                or xarm.get("warning_code") not in (None, 0)
            )
        ):
            add("xarm_alarm")
        for role in ("tool", "workspace"):
            camera = _mapping(cameras.get(role))
            if camera.get("healthy") is not True or camera.get("tone") == "danger":
                add("%s_camera_alarm" % role)
        if any(
            _mapping(operations.get(name)).get("state")
            in ("confirming", "starting", "running", "stopping")
            for name in ("petri", "recovery")
        ):
            add("operation_boundary")
        review = _mapping(operations.get("review"))
        if review.get("state") in ("pending", "ready", "confirming", "CONFIRMING") and (
            review.get("pending", 0) or review.get("action_allowed") is True
        ):
            add("manual_review_pending")
        if workspace_teach.get("valid") is True and workspace_teach.get("state") in (
            "awaiting_teach",
            "positioning",
            "ready_to_capture",
            "review",
            "invalidated",
        ):
            add("workspace_teach_boundary")

        try:
            diagnostics = _diagnostics_view(view)
        except Exception:
            diagnostics = {}
            add("diagnostics_invalid")
        workers = diagnostics.get("workers") if isinstance(diagnostics, dict) else ()
        if isinstance(workers, list) and any(
            item.get("configured") is True and item.get("running") is not True
            for item in workers
            if isinstance(item, dict)
        ):
            add("worker_stopped")
        datahub = _mapping(diagnostics.get("datahub"))
        if datahub.get("configured") is True and (
            datahub.get("available") is not True
            or datahub.get("dataset_binding_verified") is not True
            or bool(datahub.get("dead_letters"))
        ):
            add("datahub_alarm")

        # Danger is rendered as an operator alarm throughout the reducers.
        alarm_views = (
            view,
            ota,
            capture,
            search,
            safety,
            motion,
            xarm,
            digital_twin,
            workspace_teach,
            workspace_boundary,
        )
        if any(item.get("tone") == "danger" for item in alarm_views):
            add("rendered_danger")
        for name in (
            "petri",
            "recovery",
            "registration",
            "datahub",
            "identity",
            "history",
        ):
            if _mapping(operations.get(name)).get("tone") == "danger":
                add("operation_alarm")
        return tuple(reasons)

    def _screensaver_visibility_blocked(self):
        """Fail open to safety/status visibility for every active boundary."""

        return bool(self._screensaver_visibility_reasons())

    def screensaver_reveal_diagnostics(self):
        """Return secret-free pixel-overlay timing evidence for commissioning."""

        poll_ms = int(self.config.get("poll_ms", DEFAULT_POLL_MS))
        timeout_ms = int(self.config.get("timeout_ms", DEFAULT_TIMEOUT_MS))
        return {
            "schema_version": SCREENSAVER_REVEAL_DIAGNOSTIC_SCHEMA_VERSION,
            "measurement_scope": "lvgl_pixel_overlay",
            "safety_rated": False,
            "backlight_control": False,
            "configured_reveal_bound_ms": (
                poll_ms + timeout_ms + COMPLETION_CHECK_MS + SCREENSAVER_CHECK_MS
            ),
            "reveal_count": min(
                max(int(getattr(self, "_screensaver_reveal_count", 0)), 0),
                MAX_SCREENSAVER_REVEAL_COUNT,
            ),
            "last_reason": _safe_text(
                getattr(self, "_screensaver_last_reveal_reason", ""), 48
            ),
            "last_local_reveal_ms": getattr(
                self, "_screensaver_last_reveal_local_ms", None
            ),
            "last_poll_sample_ms": getattr(
                self, "_screensaver_last_reveal_poll_ms", None
            ),
            "max_poll_sample_ms": getattr(
                self, "_screensaver_max_reveal_poll_ms", None
            ),
            "visibility_reasons": tuple(
                getattr(self, "_screensaver_last_visibility_reasons", ())
            )[:32],
        }

    def _record_screensaver_reveal(self, reason, observed_ms, revealed_ms):
        local_ms = _elapsed_ms(observed_ms, revealed_ms)
        poll_started_ms = getattr(self, "_pending_health_poll_started_ms", None)
        poll_ms = (
            _elapsed_ms(poll_started_ms, revealed_ms)
            if isinstance(poll_started_ms, int)
            and not isinstance(poll_started_ms, bool)
            else None
        )
        self._screensaver_reveal_count = min(
            int(getattr(self, "_screensaver_reveal_count", 0)) + 1,
            MAX_SCREENSAVER_REVEAL_COUNT,
        )
        self._screensaver_last_reveal_reason = reason
        self._screensaver_last_reveal_local_ms = local_ms
        self._screensaver_last_reveal_poll_ms = poll_ms
        maximum = getattr(self, "_screensaver_max_reveal_poll_ms", None)
        if poll_ms is not None and (maximum is None or poll_ms > maximum):
            self._screensaver_max_reveal_poll_ms = poll_ms
        diagnostic = self.screensaver_reveal_diagnostics()
        print(
            "LABCOBOT_LVGL_SCREENSAVER_REVEAL scope=pixel_overlay "
            "reason=%s local_ms=%d poll_sample_ms=%s bound_ms=%d "
            "safety_rated=0 backlight_control=0"
            % (
                diagnostic["last_reason"] or "unknown",
                local_ms,
                str(poll_ms) if poll_ms is not None else "none",
                diagnostic["configured_reveal_bound_ms"],
            )
        )

    def _enforce_screensaver_visibility(self, now_ms=None):
        """Immediately reveal any new safety, alarm, or active-work state."""

        now = _monotonic_ms() if now_ms is None else int(now_ms)
        reasons = self._screensaver_visibility_reasons()
        was_blocked = bool(getattr(self, "_screensaver_visibility_blocked_last", True))
        self._screensaver_last_visibility_reasons = reasons
        if not reasons:
            self._screensaver_visibility_blocked_last = False
            if was_blocked:
                # A cleared alarm starts a complete new idle interval.  Time
                # spent behind an alarm can never count toward blanking.
                self._record_interaction(now_ms=now)
            return True
        self._screensaver_visibility_blocked_last = True
        if getattr(self, "_screensaver_active", False):
            observed = _monotonic_ms()
            guard_wake = bool(
                getattr(self, "_screensaver_wake_guard", False)
                or getattr(self, "_input_activity_pressed", False)
                or getattr(self, "_input_uncertain_contact", False)
            )
            self._hide_screensaver(now_ms=now, guard_wake=guard_wake)
            self._record_screensaver_reveal(reasons[0], observed, _monotonic_ms())
        else:
            self._record_interaction(now_ms=now)
        return False

    def _show_screensaver(self):
        if not getattr(self, "_screensaver_capability_enabled", True):
            return False
        if self._screensaver_visibility_blocked():
            return False
        overlay = getattr(self, "screensaver_overlay", None)
        if overlay is None:
            return False
        self._clear_tenant_password(getattr(self, "tenant_auth_password_input", None))
        overlay.remove_flag(self.lv.obj.FLAG.HIDDEN)
        if not self._foreground_screensaver_overlay():
            # Keep every underlying action generation disabled when the opaque
            # wake target cannot be proven foreground for this layout.
            self._layout_input_ready = False
            return False
        self._screensaver_active = True
        screen = getattr(self, "screen", None)
        if screen is not None:
            screen.invalidate()
        return True

    def _hide_screensaver(self, now_ms=None, guard_wake=False):
        overlay = getattr(self, "screensaver_overlay", None)
        if overlay is not None:
            overlay.add_flag(self.lv.obj.FLAG.HIDDEN)
        self._screensaver_active = False
        self._screensaver_wake_guard = bool(guard_wake)
        self._record_interaction(now_ms=now_ms)
        screen = getattr(self, "screen", None)
        if screen is not None:
            screen.invalidate()

    def _wake_screensaver(self, event=None):
        if not self._clicked(event) or not getattr(self, "_screensaver_active", False):
            return False
        self._hide_screensaver(guard_wake=True)
        return True

    def _check_screensaver(self, _timer=None, now_ms=None):
        now = _monotonic_ms() if now_ms is None else int(now_ms)
        self._poll_input_activity(now_ms=now)
        # This clears only after LVGL has returned from the wake event dispatch,
        # preventing that physical tap from crossing an underlying callback.
        if not getattr(self, "_input_activity_pressed", False) and not getattr(
            self, "_input_uncertain_contact", False
        ):
            self._screensaver_wake_guard = False
        if not self._enforce_screensaver_visibility(now_ms=now):
            return False
        if getattr(self, "_screensaver_active", False):
            return True
        timeout_ms = int(self.config["screensaver_timeout_seconds"]) * 1000
        elapsed = _elapsed_ms(
            getattr(self, "_last_interaction_ms", now),
            now,
        )
        if elapsed >= timeout_ms:
            return self._show_screensaver()
        return False

    def _clear_workspace_teach_finalize_challenge(self):
        self._workspace_teach_finalize_challenge = ""
        self._workspace_teach_finalize_digest = ""
        self._workspace_teach_finalize_session_id = ""
        self._workspace_teach_finalize_started_ms = 0

    def _workspace_teach_confirmation_current(self, teach, now_ms=None):
        """Require the local token to remain bound to one review snapshot."""

        teach = _mapping(teach)
        if (
            teach.get("valid") is not True
            or teach.get("state") != "review"
            or not _lower_hex(
                getattr(self, "_workspace_teach_finalize_challenge", ""),
                32,
            )
            or not _lower_hex(
                getattr(self, "_workspace_teach_finalize_digest", ""),
                64,
            )
            or not _lower_hex(
                getattr(self, "_workspace_teach_finalize_session_id", ""),
                32,
            )
            or teach.get("proposal_sha256")
            != getattr(self, "_workspace_teach_finalize_digest", "")
            or teach.get("session_id")
            != getattr(self, "_workspace_teach_finalize_session_id", "")
        ):
            return False
        now = _monotonic_ms() if now_ms is None else int(now_ms)
        return (
            _elapsed_ms(
                getattr(self, "_workspace_teach_finalize_started_ms", 0),
                now,
            )
            < 5000
        )

    def _workspace_teach_primary_click(self, event=None):
        self._start_async_flow(
            "workspace-teach",
            self._workspace_teach_primary_flow(event),
        )

    def _workspace_teach_primary_flow(self, event=None):
        """Run one fixed teach action derived solely from sanitized health.

        A single review click drives both bound backend finalize phases. The
        short-lived challenge is validated and consumed inside this generator;
        it is never exposed as a second-click UI state.
        """

        if not self._clicked(event) or getattr(
            self, "_workspace_teach_request_pending", False
        ):
            return
        teach = _mapping(getattr(self, "_last_workspace_teach_view", {}))
        if teach.get("valid") is not True:
            return
        state = teach.get("state")
        operation = ""

        if state in ("idle", "cancelled"):
            # The first touch is an explicit local acknowledgement of the
            # fixed warning. It is deliberately transport-free.
            if not getattr(self, "_workspace_teach_notice_acknowledged", False):
                self._workspace_teach_notice_acknowledged = True
                self._apply_workspace_teach(
                    {"workspace_teach": self._last_workspace_teach_view}
                )
                screen = getattr(self, "screen", None)
                if screen is not None:
                    screen.invalidate()
                return
            operation = "workspace_teach_start"
        elif state == "ready_to_capture":
            if (
                teach.get("pose_ready") is not True
                or teach.get("blockers")
                or teach.get("mode_two_blocked") is True
            ):
                return
            operation = "workspace_teach_capture"
        elif state == "review":
            operation = "workspace_teach_finalize"
        else:
            return

        self._clear_workspace_teach_finalize_challenge()
        self._begin_action()
        self._workspace_teach_request_pending = True
        self._apply_workspace_teach(
            {"workspace_teach": self._last_workspace_teach_view}
        )
        if operation == "workspace_teach_start":
            request = request_workspace_teach_start(
                self.config["health_url"],
                self.config["timeout_ms"],
            )
        elif operation == "workspace_teach_capture":
            request = request_workspace_teach_capture(
                self.config["health_url"],
                self.config["timeout_ms"],
            )
        else:
            request = request_workspace_teach_finalize(
                self.config["health_url"],
                challenge=None,
                timeout_ms=self.config["timeout_ms"],
            )
        response = yield request
        response = _mapping(response)
        status_code = response.get("http_status")
        payload = _mapping(response.get("payload"))
        valid = bool(
            not isinstance(status_code, bool)
            and isinstance(status_code, int)
            and _valid_completed_transport_payload(
                operation,
                status_code,
                payload,
            )
        )
        outcome = payload.get("status") if valid else ""
        self._workspace_teach_request_pending = False

        if operation == "workspace_teach_finalize":
            current_teach = _mapping(getattr(self, "_last_workspace_teach_view", {}))
            if not (
                valid
                and status_code == 202
                and outcome == "confirm"
                and payload.get("proposal_sha256") == teach.get("proposal_sha256")
                and teach.get("state") == "review"
                and _lower_hex(teach.get("session_id"), 32)
                and current_teach.get("state") == "review"
                and current_teach.get("session_id") == teach.get("session_id")
                and current_teach.get("proposal_sha256") == teach.get("proposal_sha256")
            ):
                self._clear_workspace_teach_finalize_challenge()
                self._apply_workspace_teach(
                    {"workspace_teach": self._last_workspace_teach_view}
                )
                return

            self._workspace_teach_finalize_challenge = payload["challenge"]
            self._workspace_teach_finalize_digest = payload["proposal_sha256"]
            self._workspace_teach_finalize_session_id = teach["session_id"]
            self._workspace_teach_finalize_started_ms = _monotonic_ms()
            if not self._workspace_teach_confirmation_current(current_teach):
                self._clear_workspace_teach_finalize_challenge()
                self._apply_workspace_teach(
                    {"workspace_teach": self._last_workspace_teach_view}
                )
                return

            # One use only: consume before phase two crosses the process
            # boundary. STOP may still invalidate the pending broker callback
            # through the action epoch, and the server also binds STOP state.
            challenge = self._workspace_teach_finalize_challenge
            self._clear_workspace_teach_finalize_challenge()
            self._workspace_teach_request_pending = True
            # Phase two may persist successfully even when the broker loses
            # its reply.  Record the exact health correlation before crossing
            # that boundary; only authoritative health may later promote it.
            self._workspace_teach_waiting = {
                "operation": operation,
                "session_id": teach.get("session_id"),
                "completed_steps": teach.get("completed_steps"),
                "proposal_sha256": teach.get("proposal_sha256"),
            }
            second_response = yield request_workspace_teach_finalize(
                self.config["health_url"],
                challenge=challenge,
                timeout_ms=self.config["timeout_ms"],
            )
            second_response = _mapping(second_response)
            second_status = second_response.get("http_status")
            second_payload = _mapping(second_response.get("payload"))
            second_valid = bool(
                not isinstance(second_status, bool)
                and isinstance(second_status, int)
                and _valid_completed_transport_payload(
                    "workspace_teach_finalize",
                    second_status,
                    second_payload,
                )
            )
            if not (
                second_valid
                and second_status == 200
                and second_payload.get("status") == "proposed"
                and second_payload.get("proposal_sha256")
                == teach.get("proposal_sha256")
            ):
                ambiguous_delivery = bool(
                    second_status in (None, 0) or second_response.get("transport_error")
                )
                if not ambiguous_delivery:
                    self._workspace_teach_request_pending = False
                    self._workspace_teach_waiting = {}
                self._apply_workspace_teach(
                    {"workspace_teach": self._last_workspace_teach_view}
                )
                return

        if valid and (
            operation == "workspace_teach_finalize"
            or (
                operation in ("workspace_teach_start", "workspace_teach_capture")
                and status_code == 202
                and outcome == "accepted"
            )
        ):
            self._workspace_teach_waiting = {
                "operation": operation,
                "session_id": teach.get("session_id"),
                "completed_steps": teach.get("completed_steps"),
                "proposal_sha256": teach.get("proposal_sha256"),
            }
            self._workspace_teach_request_pending = True
            if operation == "workspace_teach_start":
                self._workspace_teach_notice_acknowledged = False

        self._apply_workspace_teach(
            {"workspace_teach": self._last_workspace_teach_view}
        )
        screen = getattr(self, "screen", None)
        if screen is not None:
            screen.invalidate()

    def _workspace_teach_cancel_click(self, event=None):
        self._start_async_flow(
            "workspace-teach",
            self._workspace_teach_cancel_flow(event),
        )

    def _workspace_teach_cancel_flow(self, event=None):
        if not self._clicked(event) or getattr(
            self, "_workspace_teach_request_pending", False
        ):
            return
        teach = _mapping(getattr(self, "_last_workspace_teach_view", {}))
        if teach.get("valid") is not True or teach.get("state") not in (
            "awaiting_teach",
            "positioning",
            "ready_to_capture",
            "review",
            "invalidated",
        ):
            return
        self._clear_workspace_teach_finalize_challenge()
        self._begin_action()
        self._workspace_teach_request_pending = True
        self._apply_workspace_teach(
            {"workspace_teach": self._last_workspace_teach_view}
        )
        response = yield request_workspace_teach_cancel(
            self.config["health_url"],
            self.config["timeout_ms"],
        )
        response = _mapping(response)
        status_code = response.get("http_status")
        payload = _mapping(response.get("payload"))
        valid = bool(
            not isinstance(status_code, bool)
            and isinstance(status_code, int)
            and _valid_completed_transport_payload(
                "workspace_teach_cancel", status_code, payload
            )
        )
        self._workspace_teach_request_pending = False
        if valid and status_code == 200 and payload.get("status") == "cancelled":
            self._workspace_teach_waiting = {
                "operation": "workspace_teach_cancel",
                "session_id": teach.get("session_id"),
                "completed_steps": teach.get("completed_steps"),
                "proposal_sha256": teach.get("proposal_sha256"),
            }
            self._workspace_teach_request_pending = True
            self._workspace_teach_notice_acknowledged = False
        self._apply_workspace_teach(
            {"workspace_teach": self._last_workspace_teach_view}
        )
        screen = getattr(self, "screen", None)
        if screen is not None:
            screen.invalidate()

    @staticmethod
    def _tenant_input_text(widget, maximum):
        getter = getattr(widget, "get_text", None)
        if not callable(getter):
            return ""
        try:
            value = str(getter() or "")
        except Exception:
            return ""
        return value[:maximum]

    @staticmethod
    def _clear_tenant_password(widget):
        setter = getattr(widget, "set_text", None)
        if callable(setter):
            try:
                setter("")
            except Exception:
                pass

    def _tenant_auth_login_click(self, event=None):
        self._start_async_flow(
            "tenant-auth",
            self._tenant_auth_login_flow(event),
        )

    def _tenant_auth_login_flow(self, event=None):
        if (
            not self._clicked(event)
            or getattr(self, "_tenant_auth_request_pending", False)
            or not getattr(self, "tenant_auth_input_supported", False)
        ):
            return
        tenant_url = self._tenant_input_text(
            getattr(self, "tenant_auth_tenant_input", None),
            512,
        ).strip()
        username = self._tenant_input_text(
            getattr(self, "tenant_auth_username_input", None),
            254,
        ).strip()
        password_widget = getattr(self, "tenant_auth_password_input", None)
        password = self._tenant_input_text(password_widget, 128)
        try:
            request = request_tenant_login(
                self.config["health_url"],
                tenant_url,
                username,
                password,
                timeout_ms=self.config["timeout_ms"],
            )
        except (TypeError, ValueError):
            self._clear_tenant_password(password_widget)
            self._tenant_auth_local_status = "invalid_request"
            self._apply_tenant_auth(getattr(self, "_last_view", {}))
            return
        # The password must not remain visible or retained by the widget after
        # the explicit tap. The immutable broker request owns the only
        # remaining short-lived copy inside the private 0700 /run mailbox.
        self._clear_tenant_password(password_widget)
        password = ""
        self._tenant_auth_request_pending = True
        self._tenant_auth_local_status = "signing_in"
        self._apply_tenant_auth(getattr(self, "_last_view", {}))
        response = yield request
        response = _mapping(response)
        status_code = response.get("http_status")
        payload = _mapping(response.get("payload"))
        valid = bool(
            not isinstance(status_code, bool)
            and isinstance(status_code, int)
            and _valid_completed_transport_payload(
                "tenant_login",
                status_code,
                payload,
            )
        )
        completed = bool(
            valid and status_code == 200 and payload.get("status") == "authenticated"
        )
        if completed:
            registration = _mapping(payload.get("device_registration"))
            if registration:
                self._tenant_device_registration = dict(registration)
        self._tenant_auth_request_pending = completed
        self._tenant_auth_local_status = (
            "awaiting_health"
            if completed
            else (
                _safe_text(payload.get("status") or "invalid_response", 64)
                if valid
                else "invalid_response"
            )
        )
        self._tenant_auth_waiting = (
            {
                "operation": "tenant_login",
                "tenant_url": payload.get("tenant_url"),
                "tenant": payload.get("tenant"),
                "username": payload.get("username"),
            }
            if completed
            else {}
        )
        self._apply_tenant_auth(getattr(self, "_last_view", {}))
        screen = getattr(self, "screen", None)
        if screen is not None:
            screen.invalidate()

    def _tenant_auth_logout_click(self, event=None):
        self._start_async_flow(
            "tenant-auth",
            self._tenant_auth_logout_flow(event),
        )

    def _tenant_auth_logout_flow(self, event=None):
        if not self._clicked(event) or getattr(
            self, "_tenant_auth_request_pending", False
        ):
            return
        self._tenant_auth_request_pending = True
        self._tenant_auth_local_status = "signing_out"
        self._clear_tenant_password(getattr(self, "tenant_auth_password_input", None))
        self._apply_tenant_auth(getattr(self, "_last_view", {}))
        response = yield request_tenant_logout(
            self.config["health_url"],
            self.config["timeout_ms"],
        )
        response = _mapping(response)
        status_code = response.get("http_status")
        payload = _mapping(response.get("payload"))
        valid = bool(
            not isinstance(status_code, bool)
            and isinstance(status_code, int)
            and _valid_completed_transport_payload(
                "tenant_logout",
                status_code,
                payload,
            )
        )
        completed = bool(
            valid and status_code == 200 and payload.get("status") == "logged_out"
        )
        if completed:
            self._tenant_device_registration = {}
        self._tenant_auth_request_pending = completed
        self._tenant_auth_local_status = (
            "awaiting_health"
            if completed
            else (
                _safe_text(payload.get("status") or "invalid_response", 64)
                if valid
                else "invalid_response"
            )
        )
        self._tenant_auth_waiting = {"operation": "tenant_logout"} if completed else {}
        self._apply_tenant_auth(getattr(self, "_last_view", {}))
        screen = getattr(self, "screen", None)
        if screen is not None:
            screen.invalidate()

    def _motion_search_click(self, _event=None):
        self._start_async_flow(
            "motion-search",
            self._motion_search_flow(_event),
        )

    def _motion_search_flow(self, _event=None):
        """Request only the fixed backend-reviewed two-step search path."""

        if not self._clicked(_event):
            return
        if getattr(self, "_motion_stop_latched", False):
            self._software_stop_click(_event)
            return
        if self._motion_search_request_pending:
            return
        search = self._last_motion_search_view
        challenge = self._motion_search_challenge
        second_confirmation = bool(challenge)
        # The first touch may ask the authoritative backend for its current
        # gate result even when the last health sample was locked.  Only a
        # valid backend-issued challenge can reach the confirming touch.
        if not second_confirmation and search.get("request_allowed") is not True:
            return
        if second_confirmation and search.get("configured") is not True:
            self._motion_search_challenge = ""
            return

        # The backend may admit motion even if the broker reply is lost. Empty
        # the single-use token and expose universal STOP before crossing the
        # process boundary on the confirming touch.
        if second_confirmation:
            self._motion_search_challenge = ""
            self._motion_stop_latched = True
            self._motion_stop_origin = "search"
        self._begin_action()
        self._motion_search_request_pending = True
        optimistic = dict(search)
        optimistic.update(
            {
                "action_allowed": False,
                "request_allowed": False,
                "request_result": "checking",
                "tone": "danger" if second_confirmation else "warn",
                "headline": (
                    "STARTSTATUS UNBEKANNT - STOP BEREIT"
                    if second_confirmation
                    else "SAFETY-GATES WERDEN GEPRUEFT"
                ),
                "detail": (
                    "Universal STOP bleibt aktiv bis LOCKED bestaetigt ist"
                    if second_confirmation
                    else "Erste Bestaetigung wird serverseitig gebunden"
                ),
                "button": "SOFTWARE STOP" if second_confirmation else "BITTE WARTEN",
                "workflow_progress": 75 if second_confirmation else 37,
                "workflow_stage": (
                    "3 / 4  FREIGABE WIRD UEBERTRAGEN"
                    if second_confirmation
                    else "2 / 4  SERVER-SAFETY-CHECK"
                ),
                "stop_allowed": second_confirmation,
            }
        )
        self._last_motion_search_view = optimistic
        self._apply_system(self._last_view)
        self._apply_digital_twin(getattr(self, "_last_view", {}))
        self._apply_software_stop_nav(self._last_capture_view)

        response = yield request_motion_search(
            self.config["health_url"],
            challenge=challenge if second_confirmation else None,
            timeout_ms=self.config["timeout_ms"],
        )
        response = _mapping(response)
        payload = _mapping(response.get("payload"))
        try:
            status_code = int(response.get("http_status") or 0)
        except (TypeError, ValueError):
            status_code = 0
        outcome = _safe_text(payload.get("status") or "error", 24)

        result = dict(optimistic)
        if status_code == 202 and outcome == "confirm" and not second_confirmation:
            token = payload.get("challenge")
            expires = payload.get("expires_in_seconds")
            if (
                isinstance(token, str)
                and len(token) == 32
                and all(value in "0123456789abcdef" for value in token)
                and isinstance(expires, int)
                and not isinstance(expires, bool)
                and 1 <= expires <= 5
                and self._remember_challenge(
                    "_motion_search_challenge",
                    token,
                    expires,
                    ("motion-search", int(getattr(self, "_action_epoch", 0))),
                )
            ):
                result.update(
                    {
                        "configured": True,
                        "action_allowed": True,
                        "request_allowed": True,
                        "request_result": "confirm",
                        "state": "ready",
                        "tone": "warn",
                        "headline": "WERKZEUGSUCHE ERNEUT BESTAETIGEN",
                        "detail": "Arbeitsraum frei und physischer Not-Aus erreichbar?",
                        "button": "NOCHMAL BESTAETIGEN",
                        "workflow_progress": 50,
                        "workflow_stage": "2 / 4  ZWEITE BESTAETIGUNG",
                        "stop_allowed": False,
                    }
                )
            else:
                result.update(
                    {
                        "action_allowed": False,
                        "request_allowed": True,
                        "request_result": "invalid_confirmation",
                        "tone": "danger",
                        "headline": "BESTAETIGUNG UNGUELTIG",
                        "detail": "Backend-Vertrag konnte nicht validiert werden",
                        "button": "SAFETY-GATES PRUEFEN",
                        "workflow_progress": 0,
                        "workflow_stage": "0 / 4  BESTAETIGUNG UNGUELTIG",
                        "stop_allowed": False,
                    }
                )
        elif status_code == 202 and outcome == "accepted" and second_confirmation:
            self._motion_stop_latched = True
            self._motion_stop_origin = "search"
            result.update(
                {
                    "action_allowed": False,
                    "request_allowed": False,
                    "request_result": "accepted",
                    "state": "armed_live",
                    "tone": "danger",
                    "headline": "WERKZEUGSUCHE FREIGEGEBEN",
                    "detail": "Genau ein validierter Suchlauf; STOP ist sofort bereit",
                    "button": "SOFTWARE STOP",
                    "workflow_progress": 75,
                    "workflow_stage": "3 / 4  ROBOTER-SUCHLAUF AKTIV",
                    "stop_allowed": True,
                }
            )
        elif second_confirmation:
            # Transport failure or rejection after the confirmation boundary
            # cannot prove that the backend did not admit motion.
            self._motion_stop_latched = True
            self._motion_stop_origin = "search"
            exact_result = (
                outcome.upper()
                if status_code
                and outcome
                in (
                    "confirmation_required",
                    "busy",
                    "unsafe",
                    "unavailable",
                    "error",
                )
                else "NO RESPONSE"
            )
            result.update(
                {
                    "action_allowed": False,
                    "request_allowed": False,
                    "request_result": (outcome if status_code else "transport_error"),
                    "state": "armed_live",
                    "tone": "danger",
                    "headline": "BACKEND GATE: %s / STOP READY" % exact_result,
                    "detail": (
                        "Exact backend result received; STOP remains latched"
                        if status_code
                        else "No response; Universal STOP can be repeated"
                    ),
                    "button": "SOFTWARE STOP",
                    "workflow_progress": 75,
                    "workflow_stage": "3 / 4  GATE %s / STOP READY" % exact_result,
                    "stop_allowed": True,
                }
            )
        elif status_code == 202 and outcome == "accepted":
            # The documented contract cannot admit on the first request.  If
            # it ever does, treat it as live and expose STOP immediately.
            self._motion_stop_latched = True
            self._motion_stop_origin = "search"
            result.update(
                {
                    "action_allowed": False,
                    "request_allowed": False,
                    "request_result": "accepted",
                    "state": "armed_live",
                    "tone": "danger",
                    "headline": "BACKEND: ACCEPTED / STOP READY",
                    "detail": "Unexpected admission result; Universal STOP is active",
                    "button": "SOFTWARE STOP",
                    "workflow_progress": 75,
                    "workflow_stage": "3 / 4  ACCEPTED / STOP READY",
                    "stop_allowed": True,
                }
            )
        else:
            self._motion_search_challenge = ""
            known_result = bool(
                status_code
                and outcome
                in (
                    "confirmation_required",
                    "busy",
                    "unsafe",
                    "unavailable",
                    "error",
                )
            )
            exact_result = outcome.upper() if known_result else "NO RESPONSE"
            result.update(
                {
                    "action_allowed": False,
                    "request_allowed": True,
                    "request_result": outcome if known_result else "transport_error",
                    "tone": (
                        "danger" if outcome == "error" or not status_code else "warn"
                    ),
                    "headline": "BACKEND GATE RESULT: %s" % exact_result,
                    "detail": (
                        "Backend rejected the request before confirmation"
                        if known_result
                        else "Local motion backend did not return a valid response"
                    ),
                    "button": "SEARCH PATH START",
                    "workflow_progress": 0,
                    "workflow_stage": "0 / 4  GATE RESULT: %s" % exact_result,
                    "stop_allowed": False,
                }
            )
        self._last_motion_search_view = result
        self._motion_search_request_pending = False
        self._apply_system(self._last_view)
        self._apply_digital_twin(getattr(self, "_last_view", {}))
        self._apply_software_stop_nav(self._last_capture_view)
        self.screen.invalidate()

    def _safety_configuration_click(self, _event=None):
        self._start_async_flow(
            "safety-configure",
            self._safety_configuration_flow(_event),
        )

    def _safety_configuration_flow(self, _event=None):
        """Two-step request for one backend-pinned, no-motion safety profile."""

        if not self._clicked(_event) or self._safety_configuration_request_pending:
            return
        current = self._last_safety_configuration_view
        if current.get("search_ready") is True:
            self._activate_view("system")
            return
        challenge = self._safety_configuration_challenge
        second_confirmation = bool(challenge)
        if not second_confirmation and current.get("action_allowed") is not True:
            return
        if second_confirmation and not _lower_hex(
            self._safety_configuration_digest, 64
        ):
            self._safety_configuration_challenge = ""
            return
        self._begin_action()
        self._safety_configuration_request_pending = True
        optimistic = dict(current)
        optimistic.update(
            {
                "tone": "warn",
                "headline": (
                    "READBACK WIRD VERIFIZIERT"
                    if second_confirmation
                    else "PREFLIGHT WIRD SERVERSEITIG GEPRUEFT"
                ),
                "detail": (
                    "Motoren bleiben aus; Search bleibt gesperrt"
                    if second_confirmation
                    else "Pinned Profil wird an aktuelle Safety-Gates gebunden"
                ),
                "action_allowed": False,
                "button": "BITTE WARTEN",
                "configured": False,
                "exact_readback": False,
                "search_ready": False,
            }
        )
        self._last_safety_configuration_view = optimistic
        self._apply_safety_configuration(self._last_view)

        response = yield request_safety_configuration(
            self.config["health_url"],
            challenge=challenge if second_confirmation else None,
            timeout_ms=self.config["timeout_ms"],
        )
        response = _mapping(response)
        payload = _mapping(response.get("payload"))
        try:
            status_code = int(response.get("http_status") or 0)
        except (TypeError, ValueError):
            status_code = 0
        status = _safe_text(payload.get("status") or "error", 24)
        result = dict(optimistic)
        if status_code == 202 and status == "confirm" and not second_confirmation:
            token = payload.get("challenge")
            digest = payload.get("profile_sha256")
            expires = payload.get("expires_in_seconds")
            if (
                _lower_hex(token, 32)
                and _lower_hex(digest, 64)
                and isinstance(expires, int)
                and not isinstance(expires, bool)
                and 1 <= expires <= 5
                and digest == current.get("profile_sha256")
            ):
                self._safety_configuration_digest = digest
                if self._remember_challenge(
                    "_safety_configuration_challenge",
                    token,
                    expires,
                    (
                        "safety-configure",
                        int(getattr(self, "_action_epoch", 0)),
                        digest,
                    ),
                ):
                    result.update(
                        {
                            "tone": "warn",
                            "headline": "PINNED PROFIL ERNEUT BESTAETIGEN",
                            "detail": "Controller verriegelt; Motoren AUS; keine Bewegung",
                            "action_allowed": True,
                            "button": "JETZT SICHER AKTIVIEREN",
                        }
                    )
                else:
                    self._safety_configuration_digest = ""
                    result.update(
                        {
                            "tone": "danger",
                            "headline": "PROFIL-BESTAETIGUNG UNGUELTIG",
                            "detail": "Lokale Bindung konnte nicht erstellt werden",
                            "button": "ERNEUT PRUEFEN",
                            "action_allowed": True,
                        }
                    )
            else:
                self._safety_configuration_challenge = ""
                self._safety_configuration_digest = ""
                result.update(
                    {
                        "tone": "danger",
                        "headline": "PROFIL-BESTAETIGUNG UNGUELTIG",
                        "detail": "Digest oder Backend-Vertrag stimmt nicht",
                        "button": "ERNEUT PRUEFEN",
                        "action_allowed": True,
                    }
                )
        elif status_code == 200 and status == "configured" and second_confirmation:
            expected = self._safety_configuration_digest
            self._safety_configuration_challenge = ""
            self._safety_configuration_digest = ""
            if payload.get("profile_sha256") == expected:
                result.update(
                    {
                        "tone": "warn",
                        "headline": "SCHREIBVORGANG BESTAETIGT",
                        "detail": "Warte auf frischen exakten Controller-Readback",
                        "button": "READBACK AUSSTEHEND",
                        "action_allowed": False,
                    }
                )
            else:
                result.update(
                    {
                        "tone": "danger",
                        "headline": "PROFIL-DIGEST STIMMT NICHT",
                        "detail": "Search bleibt gesperrt; Controller-Readback abwarten",
                        "button": "READBACK AUSSTEHEND",
                        "action_allowed": False,
                    }
                )
        elif status_code == 409 and status == "aborted":
            self._safety_configuration_challenge = ""
            self._safety_configuration_digest = ""
            result.update(
                {
                    "tone": "warn",
                    "headline": "DURCH SOFTWARE-STOP ABGEBROCHEN",
                    "detail": "Exakten Controller-Readback abwarten; Search bleibt gesperrt",
                    "button": "READBACK PRUEFEN",
                    "action_allowed": False,
                    "configured": False,
                    "exact_readback": False,
                    "search_ready": False,
                }
            )
        else:
            self._safety_configuration_challenge = ""
            self._safety_configuration_digest = ""
            exact = status.upper() if status_code else "NO RESPONSE"
            result.update(
                {
                    "tone": "danger",
                    "headline": "SAFETY-BACKEND: %s" % exact,
                    "detail": (
                        "Controller-Readback abwarten; Search bleibt gesperrt"
                        if second_confirmation
                        else "Preflight wurde nicht freigegeben"
                    ),
                    "button": "ERNEUT PRUEFEN",
                    "action_allowed": not second_confirmation,
                    "configured": False,
                    "exact_readback": False,
                    "search_ready": False,
                }
            )
        self._last_safety_configuration_view = result
        self._safety_configuration_local_pending = True
        self._safety_configuration_request_pending = False
        self._apply_safety_configuration(self._last_view)
        self.screen.invalidate()

    def _software_stop_click(self, _event=None):
        self._start_async_flow(
            "software-stop",
            self._software_stop_flow(_event),
            stop=True,
        )

    def _hand_training_start_click(self, event=None):
        self._start_async_flow(
            "hand-training", self._hand_training_flow("start", event)
        )

    def _hand_training_tool_click(self, event=None):
        self._start_async_flow(
            "hand-training", self._hand_training_flow("tool", event)
        )

    def _hand_training_end_click(self, event=None):
        self._start_async_flow(
            "hand-training", self._hand_training_flow("end", event)
        )

    def _hand_training_flow(self, action, event=None):
        if not self._clicked(event) or self._hand_training_request_pending:
            return
        current = _mapping(_mapping(self._last_view).get("hand_training"))
        if action == "start":
            if current.get("start_allowed") is not True:
                return
            request = request_hand_training_start(
                self.config["health_url"], self.config["timeout_ms"]
            )
        elif action == "tool":
            if current.get("tool_allowed") is not True:
                return
            request = request_hand_training_tool(
                self.config["health_url"],
                not (current.get("tool_on") is True),
                self.config["timeout_ms"],
            )
        elif action == "end":
            if current.get("end_allowed") is not True:
                return
            request = request_hand_training_end(
                self.config["health_url"], self.config["timeout_ms"]
            )
        else:
            return
        self._begin_action()
        self._hand_training_request_pending = True
        self._apply_hand_training(self._last_view)
        response = yield request
        response = _mapping(response)
        payload = _mapping(response.get("payload"))
        status_code = response.get("http_status")
        operation = "hand_training_" + action
        valid = bool(
            isinstance(status_code, int)
            and not isinstance(status_code, bool)
            and _valid_completed_transport_payload(operation, status_code, payload)
        )
        self._hand_training_request_pending = False
        if not valid or payload.get("status") not in ("accepted", "idle"):
            self.hand_training_detail.set_text(
                "REQUEST: %s"
                % _safe_text(payload.get("status") or "NO RESPONSE", 32).upper()
            )
        self._apply_hand_training(self._last_view)
        self.screen.invalidate()

    def _software_stop_flow(self, _event=None):
        """One-tap idempotent stop for capture, search, Petri, and motion."""

        if not self._clicked(_event) or self._software_stop_request_pending:
            return
        # STOP is deliberately idempotent.  Never suppress the request using
        # stale/offline frontend state: the backend is the sole authority on
        # whether a physical owner is active.
        self._motion_stop_latched = True
        if not getattr(self, "_motion_stop_origin", ""):
            if (
                _mapping(getattr(self, "_last_operations_view", {})).get("stop_allowed")
                is True
            ):
                self._motion_stop_origin = (
                    "production"
                    if getattr(self, "_active_view", "") == "production"
                    else "operations"
                )
            elif (
                _mapping(getattr(self, "_last_capture_view", {})).get("stop_allowed")
                is True
            ):
                self._motion_stop_origin = "capture"
            else:
                self._motion_stop_origin = "search"
        self._motion_search_challenge = ""
        self._capture_start_challenge = ""
        self._petri_start_challenge = ""
        self._recovery_start_challenge = ""
        self._safety_configuration_challenge = ""
        self._safety_configuration_digest = ""
        self._safety_configuration_local_pending = False
        self._last_safety_configuration_view = _safety_configuration_view({})
        self._manual_review_challenge = ""
        self._manual_review_candidate = {}
        self._manual_review_preview_ready = False
        self._clear_manual_review_preview_source()
        self._apply_manual_review_page()
        self._clear_workspace_teach_finalize_challenge()
        self._workspace_teach_waiting = {}
        self._workspace_teach_request_pending = False
        self._workspace_teach_notice_acknowledged = False
        self._begin_action()
        self._software_stop_request_pending = True
        self._apply_software_stop_nav(self._last_capture_view)
        self._apply_digital_twin(getattr(self, "_last_view", {}))
        self._apply_workspace_teach(getattr(self, "_last_view", {}))

        yield request_software_stop(
            self.config["health_url"],
            self.config["timeout_ms"],
        )
        # Keep the STOP latch until authoritative locked/stationary health, but
        # permit another immediate tap if the acknowledgement is lost.
        self._software_stop_request_pending = False
        self.screen.invalidate()

    def _capture_action_click(self, _event=None):
        self._start_async_flow(
            "capture",
            self._capture_action_flow(_event),
        )

    def _capture_action_flow(self, _event=None):
        # A capture request is a physical UI action, never a lifecycle or
        # polling side effect.  LVGL supplies an event object only while
        # dispatching an actual input event; direct/timer calls fail closed.
        if _event is None:
            return
        get_code = getattr(_event, "get_code", None)
        if not callable(get_code):
            return
        try:
            if get_code() != self.lv.EVENT.CLICKED:
                return
        except Exception:
            return
        capture = self._last_capture_view
        stop_latched = getattr(self, "_motion_stop_latched", False)
        stopping = capture.get("stop_allowed") is True or stop_latched
        starting = capture.get("action_allowed") is True and not stop_latched
        if self._capture_request_pending or not (starting or stopping):
            return

        stored_challenge = getattr(self, "_capture_start_challenge", "")
        second_confirmation = (
            starting
            and capture.get("state") == "confirming"
            and _lower_hex(stored_challenge, 32)
        )
        # Close the UI safety gap *before* the admission request crosses the
        # process boundary. The backend may accept motion even if transport loses
        # the response; from this point onward only authoritative locked health
        # may remove immediate STOP access.  An explicit STOP while viewing an
        # already-active run is latched for the same reason.
        if second_confirmation or stopping:
            self._motion_stop_latched = True
            self._motion_stop_origin = "capture"
        request_challenge = stored_challenge if second_confirmation else None
        if second_confirmation:
            # The token is one-use.  Consume it locally before crossing the
            # transport boundary so a lost response can never replay a start.
            self._capture_start_challenge = ""
        self._begin_action()
        self._capture_request_pending = True
        optimistic = dict(capture)
        if stopping:
            optimistic.update(
                {
                    "active": True,
                    "action_allowed": False,
                    "stop_allowed": True,
                    "state": "stopping",
                    "tone": "danger",
                    "headline": "STOPP WIRD AUSGEFUEHRT",
                    "detail": "Bewegung wird verriegelt; STOP bleibt erreichbar",
                    "button": "BITTE WARTEN",
                }
            )
            requester = request_capture_stop
        elif second_confirmation:
            optimistic.update(
                {
                    "active": True,
                    "action_allowed": False,
                    "stop_allowed": True,
                    "state": "starting",
                    "tone": "danger",
                    "headline": "START WIRD GEPRUEFT - STOP BEREIT",
                    "detail": "Admission ist unbestaetigt; Software-STOP bleibt aktiv",
                    "button": "BITTE WARTEN",
                }
            )
            requester = request_capture_start
        else:
            optimistic.update(
                {
                    "active": False,
                    "action_allowed": False,
                    "stop_allowed": False,
                    "state": "starting",
                    "tone": "warn",
                    "headline": "START WIRD GEPRUEFT",
                    "detail": "Motion, Kameras und Dataset werden validiert",
                    "button": "BITTE WARTEN",
                }
            )
            requester = request_capture_start
        self._last_capture_view = optimistic
        last_view = getattr(self, "_last_view", None)
        if isinstance(last_view, dict):
            updated_view = dict(last_view)
            updated_view["capture"] = optimistic
            self._last_view = updated_view
        self._apply_capture(optimistic)
        apply_stop = getattr(self, "_apply_software_stop_nav", None)
        if callable(apply_stop):
            apply_stop(optimistic)
        if getattr(self, "_motion_stop_latched", False) and hasattr(self, "_overlays"):
            self._activate_view("capture", invalidate=False)

        if requester is request_capture_start:
            request = requester(
                self.config["health_url"],
                self.config["timeout_ms"],
                challenge=request_challenge,
            )
        else:
            request = requester(
                self.config["health_url"],
                self.config["timeout_ms"],
            )
        response = yield request
        response = _mapping(response)
        try:
            status = int(response.get("http_status") or 0)
        except (TypeError, ValueError):
            status = 0
        payload = _mapping(response.get("payload"))
        outcome = _safe_text(payload.get("status") or "error", 24)
        result = dict(optimistic)
        if (
            status == 202
            and outcome == "confirm"
            and not stopping
            and _lower_hex(payload.get("challenge"), 32)
        ):
            result.update(
                {
                    "active": False,
                    "action_allowed": True,
                    "stop_allowed": False,
                    "state": "confirming",
                    "tone": "warn",
                    "headline": "START ERNEUT BESTAETIGEN",
                    "detail": "Arbeitsraum frei und Not-Aus erreichbar?",
                    "button": "NOCHMAL BESTAETIGEN",
                }
            )
            expires = payload.get("expires_in_seconds")
            if self._remember_challenge(
                "_capture_start_challenge",
                payload["challenge"],
                expires,
                (
                    "capture",
                    int(getattr(self, "_action_epoch", 0)),
                    result.get("run_id") or "--",
                ),
            ):
                self._capture_request_pending = False
            else:
                self._capture_start_challenge = ""
                result.update(
                    {
                        "action_allowed": False,
                        "state": "failed",
                        "tone": "danger",
                        "headline": "BESTAETIGUNG UNGUELTIG",
                        "detail": "Lokale Ablaufbindung konnte nicht erstellt werden",
                        "button": "BITTE STATUS PRUEFEN",
                    }
                )
                self._capture_request_pending = False
        elif status == 202 and outcome == "accepted":
            self._capture_start_challenge = ""
            # Admission is the safety boundary, not the later health poll.
            # Make STOP actionable immediately during the motion lead time.
            self._motion_stop_latched = True
            self._motion_stop_origin = "capture"
            result = _latched_stop_capture(optimistic, capture)
            if stopping:
                result.update(
                    {
                        "state": "stopping",
                        "headline": "STOPP WIRD AUSGEFUEHRT",
                        "detail": "Backend hat den STOP angenommen; Verriegelung wird geprueft",
                    }
                )
            else:
                result.update(
                    {
                        "state": "starting",
                        "headline": "LAUF FREIGEGEBEN - STOP BEREIT",
                        "detail": "Motion-Watchdog aktiv; Software-STOP ist sofort bereit",
                    }
                )
            self._capture_request_pending = False
        elif getattr(self, "_motion_stop_latched", False):
            self._capture_start_challenge = ""
            # A failed, malformed, or lost response cannot prove that admission
            # or halt did not occur.  Keep STOP retryable until health proves a
            # terminal run, a locked motion gate, and a stationary xArm.
            result = _latched_stop_capture(optimistic, capture)
            result.update(
                {
                    "state": "stopping" if stopping else "running",
                    "headline": "AKTIONSSTATUS UNBEKANNT - STOP BEREIT",
                    "detail": "Backend-Antwort fehlt; Software-STOP kann wiederholt werden",
                }
            )
            self._capture_request_pending = False
        else:
            self._capture_start_challenge = ""
            result.update(
                {
                    "active": False,
                    "action_allowed": False,
                    "stop_allowed": False,
                    "state": "failed",
                    "tone": "danger",
                    "headline": "AKTION ABGELEHNT",
                    "detail": "Sicherheitsbedingungen sind nicht erfuellt",
                    "button": "BITTE STATUS PRUEFEN",
                }
            )
            self._capture_request_pending = False
        self._last_capture_view = result
        last_view = getattr(self, "_last_view", None)
        if isinstance(last_view, dict):
            updated_view = dict(last_view)
            updated_view["capture"] = result
            self._last_view = updated_view
        self._apply_capture(result)
        if callable(apply_stop):
            apply_stop(result)
        if getattr(self, "_motion_stop_latched", False) and hasattr(self, "_overlays"):
            origin = getattr(self, "_motion_stop_origin", "")
            self._activate_view(
                (
                    "system"
                    if origin == "search"
                    else origin if origin in ("operations", "production") else "capture"
                ),
                invalidate=False,
            )
        self.screen.invalidate()

    def _request_update_click(self, _event=None):
        self._start_async_flow(
            "update",
            self._request_update_flow(_event),
        )

    def _request_update_flow(self, _event=None):
        # Match the capture control's input provenance check.  A refresh,
        # lifecycle callback, or direct method invocation must never request an
        # update; only an actual LVGL CLICKED event may cross this boundary.
        if _event is None:
            return
        get_code = getattr(_event, "get_code", None)
        if not callable(get_code):
            return
        try:
            if get_code() != self.lv.EVENT.CLICKED:
                return
        except Exception:
            return
        if (
            self._update_request_pending
            or self._last_ota_view.get("action_allowed") is not True
        ):
            return
        self._begin_action()
        self._update_request_pending = True
        optimistic = dict(self._last_ota_view)
        optimistic.update(
            {
                "action_allowed": False,
                "status": "checking",
                "tone": "warn",
                "headline": "UPDATE WIRD GEPRUEFT",
                "detail": "Manifest und Signatur werden validiert",
                "button": "BITTE WARTEN",
            }
        )
        self._apply_ota(optimistic)

        response = yield request_update(
            self.config["health_url"],
            self.config["timeout_ms"],
        )
        response = _mapping(response)
        status = int(response.get("http_status") or 0)
        if status == 202:
            result = optimistic
        elif status == 409:
            result = dict(optimistic)
            result.update(
                {
                    "headline": "UPDATEPRUEFUNG LAEUFT",
                    "detail": "Eine sichere Updatepruefung ist bereits aktiv",
                }
            )
        else:
            result = dict(optimistic)
            result.update(
                {
                    "status": "error",
                    "tone": "danger",
                    "headline": "UPDATE NICHT GESTARTET",
                    "detail": "Der lokale Update-Dienst ist nicht erreichbar",
                    "button": "BITTE WARTEN",
                }
            )
        self._apply_ota(result)
        self.screen.invalidate()

    def _hero_metric(self, parent, x, y, width, eyebrow, value):
        panel_height = max(54, int(58 * min(self.scale, 1.35)))
        panel = self._panel(
            parent, x, y, width, panel_height, self.CARD, self.BORDER, 10
        )
        self._label(panel, eyebrow, 12, 8, self.DIM, self.font_small)
        value_label = self._label(panel, value, 12, 29, self.TEXT, self.font_body)
        return {"panel": panel, "value": value_label}

    def _camera_card(self, x, y, width, height, eyebrow):
        card = self._panel(self.screen, x, y, width, height, self.CARD, self.BORDER, 14)
        local_scale = min(self.scale, 1.55)
        pad = max(14, int(17 * local_scale))
        rail = self._panel(card, 0, pad, 5, height - (pad * 2), self.DIM, self.DIM, 3)
        eyebrow_label = self._label(
            card, eyebrow, pad, pad, self.MUTED, self.font_small
        )
        headline = self._label(
            card,
            "UNAVAILABLE",
            pad,
            pad + max(27, int(29 * local_scale)),
            self.TEXT,
            self.font_title,
        )
        detail = self._label(
            card,
            "No camera status received",
            pad,
            pad + max(62, int(67 * local_scale)),
            self.MUTED,
            self.font_small,
        )
        divider_y = pad + max(92, int(100 * local_scale))
        divider = self._panel(
            card, pad, divider_y, width - (pad * 2), 1, self.BORDER, self.BORDER, 0
        )
        metrics_y = divider_y + max(14, int(17 * local_scale))
        self._label(
            card,
            "LIVE PREVIEW ONLY",
            pad,
            metrics_y,
            self.DIM,
            self.font_small,
        )
        frames = self._label(
            card,
            "NOT SAVED TO DATASET",
            pad,
            metrics_y + max(21, int(22 * local_scale)),
            self.TEXT,
            self.font_body,
        )
        reconnects = self._label(
            card,
            "Reconnects  --    Errors  --",
            pad,
            metrics_y + max(49, int(52 * local_scale)),
            self.MUTED,
            self.font_small,
        )
        badge_height = 30
        badge_width = min(width - (pad * 2), 150)
        badge = self._panel(
            card,
            pad,
            height - pad - badge_height,
            badge_width,
            badge_height,
            self.DIM,
            self.DIM,
            badge_height // 2,
        )
        badge_label = self._label(
            badge, "NOT AVAILABLE", 0, 0, self.INK, self.font_small
        )
        badge_label.align(self.lv.ALIGN.CENTER, 0, 0)
        return {
            "card": card,
            "rail": rail,
            "eyebrow": eyebrow_label,
            "headline": headline,
            "detail": detail,
            "divider": divider,
            "frames": frames,
            "reconnects": reconnects,
            "badge": badge,
            "badge_label": badge_label,
        }

    def _motion_card(self, x, y, width, height):
        card = self._panel(self.screen, x, y, width, height, self.CARD, self.BORDER, 14)
        local_scale = min(self.scale, 1.55)
        pad = max(14, int(17 * local_scale))
        rail = self._panel(card, 0, pad, 5, height - (pad * 2), self.DIM, self.DIM, 3)
        self._label(card, "ROBOT SAFETY", pad, pad, self.MUTED, self.font_small)
        headline = self._label(
            card,
            "STATUS UNKNOWN",
            pad,
            pad + max(27, int(29 * local_scale)),
            self.TEXT,
            self.font_title,
        )
        detail = self._label(
            card,
            "No motion safety status received",
            pad,
            pad + max(62, int(67 * local_scale)),
            self.MUTED,
            self.font_small,
        )
        divider_y = pad + max(92, int(100 * local_scale))
        divider = self._panel(
            card, pad, divider_y, width - (pad * 2), 1, self.BORDER, self.BORDER, 0
        )
        policy_y = divider_y + max(14, int(17 * local_scale))
        self._label(card, "CONTROL POLICY", pad, policy_y, self.DIM, self.font_small)
        policy = self._label(
            card,
            "Verify the local runtime",
            pad,
            policy_y + max(22, int(24 * local_scale)),
            self.TEXT,
            self.font_body,
        )
        self._label(
            card,
            "Bounded controls are available only on Button 03",
            pad,
            policy_y + max(52, int(55 * local_scale)),
            self.MUTED,
            self.font_small,
        )
        badge_height = 30
        badge_width = min(width - (pad * 2), 190)
        badge = self._panel(
            card,
            pad,
            height - pad - badge_height,
            badge_width,
            badge_height,
            self.DIM,
            self.DIM,
            badge_height // 2,
        )
        badge_label = self._label(
            badge, "NOT VERIFIED", 0, 0, self.INK, self.font_small
        )
        badge_label.align(self.lv.ALIGN.CENTER, 0, 0)
        return {
            "card": card,
            "rail": rail,
            "headline": headline,
            "detail": detail,
            "divider": divider,
            "policy": policy,
            "badge": badge,
            "badge_label": badge_label,
        }

    def _tone_color(self, tone):
        if tone == "ok":
            return self.OK
        if tone == "warn":
            return self.WARN
        if tone == "danger":
            return self.DANGER
        return self.DIM

    def _set_panel_color(self, panel, color):
        panel.set_style_bg_color(self.lv.color_hex(color), 0)
        panel.set_style_border_color(self.lv.color_hex(color), 0)

    def _apply_launcher(self, view):
        states = _launcher_view(view)
        for key, widgets in self.launcher_buttons.items():
            state = states[key]
            color = self._tone_color(state["tone"])
            button = widgets["button"]
            button.set_style_bg_color(self.lv.color_hex(self.CARD), 0)
            button.set_style_border_color(self.lv.color_hex(color), 0)
            button.set_style_border_width(3, 0)
            widgets["status"].set_text(state["status"])
            widgets["status"].set_style_text_color(self.lv.color_hex(color), 0)
            if state["enabled"]:
                button.remove_state(self.lv.STATE.DISABLED)
            else:
                # Navigation buttons remain inspectable. Destination-page
                # action controls enforce the actual robot/capture gates.
                button.remove_state(self.lv.STATE.DISABLED)

    def _apply_hand_training(self, view):
        if not hasattr(self, "hand_training_state"):
            return
        training = _mapping(_mapping(view).get("hand_training"))
        state = _safe_text(training.get("state") or "unavailable", 24).upper()
        active = training.get("active") is True
        pending = getattr(self, "_hand_training_request_pending", False)
        tone = (
            "danger"
            if active
            else "ok"
            if training.get("uploaded") is True
            else "warn"
            if training.get("configured") is True
            else "muted"
        )
        color = self._tone_color(tone)
        self.hand_training_state.set_text(
            "PLEASE WAIT" if pending else state
        )
        self.hand_training_state.set_style_text_color(self.lv.color_hex(color), 0)
        if state == "COMPLETED" and training.get("uploaded") is True:
            detail = "Uploaded to DataHub; Workbench rows %d, Shortcut jobs %d" % (
                training.get("workbench_rows") or 0,
                training.get("shortcut_jobs") or 0,
            )
        elif state == "FAILED":
            detail = "Recording failed: %s" % _safe_text(
                training.get("error_code") or "unknown", 48
            )
        elif active:
            detail = "Both cameras, tool labels, metrics and TCP coordinates are recording."
        else:
            detail = "Start requires tenant login, both cameras and xArm Teach Mode 2."
        self.hand_training_detail.set_text(detail)
        self.hand_training_progress.set_text(
            "%d SAMPLES  /  %.1f S  /  %.1f HZ"
            % (
                training.get("sample_count") or 0,
                training.get("elapsed_seconds") or 0.0,
                training.get("sample_rate_hz") or 0.0,
            )
        )
        actions = (
            (
                self.hand_training_start_button,
                training.get("start_allowed") is True and not pending,
            ),
            (
                self.hand_training_tool_button,
                training.get("tool_allowed") is True and not pending,
            ),
            (
                self.hand_training_end_button,
                training.get("end_allowed") is True and not pending,
            ),
        )
        self.hand_training_tool_button["label"].set_text(
            "TOOL OFF" if training.get("tool_on") is True else "TOOL ON"
        )
        for widgets, enabled in actions:
            if enabled:
                widgets["button"].remove_state(self.lv.STATE.DISABLED)
            else:
                widgets["button"].add_state(self.lv.STATE.DISABLED)

    def _render_digital_twin(self, twin):
        if not hasattr(self, "twin_workspace_lines"):
            return False
        all_slots = (
            self.twin_workspace_lines
            + self.twin_arm_lines
            + self.twin_path_lines
            + self.twin_axis_lines
        )
        for slot in all_slots:
            self._hide_twin_segment(slot)
        for marker in self.twin_joint_markers:
            marker.add_flag(self.lv.obj.FLAG.HIDDEN)
        # v1 carries a scalar nearest-obstacle distance, not a 3D position.
        self.twin_obstacle_marker.add_flag(self.lv.obj.FLAG.HIDDEN)

        if twin.get("valid") is not True:
            self.twin_renderer_notice.set_text("VALIDATED 3D GEOMETRY UNAVAILABLE")
            self.twin_renderer_notice.remove_flag(self.lv.obj.FLAG.HIDDEN)
            return False
        if not getattr(self, "twin_line_supported", False):
            self.twin_renderer_notice.set_text("PINNED LVGL LINE RENDERER UNAVAILABLE")
            self.twin_renderer_notice.remove_flag(self.lv.obj.FLAG.HIDDEN)
            return False
        projection = getattr(self, "_twin_projection", "isometric")
        geometry = _project_digital_twin_geometry(
            twin,
            projection,
            self.twin_viewport_width,
            self.twin_viewport_height,
        )
        if geometry.get("valid") is not True:
            self.twin_renderer_notice.set_text("3D PROJECTION FAILED CLOSED")
            self.twin_renderer_notice.remove_flag(self.lv.obj.FLAG.HIDDEN)
            return False

        rendered = True
        for index, edge in enumerate(geometry["workspace_edges"]):
            rendered = (
                self._set_twin_segment(
                    self.twin_workspace_lines[index], edge[0], edge[1]
                )
                and rendered
            )
        arm = geometry["arm"]
        for index in range(len(arm) - 1):
            rendered = (
                self._set_twin_segment(
                    self.twin_arm_lines[index], arm[index], arm[index + 1]
                )
                and rendered
            )
        path = geometry["path"]
        path_color = self.OK if twin.get("admission_ready") is True else self.WARN
        for index in range(min(len(path) - 1, len(self.twin_path_lines))):
            line = self.twin_path_lines[index].get("line")
            set_color = getattr(line, "set_style_line_color", None)
            if callable(set_color):
                try:
                    set_color(self.lv.color_hex(path_color), 0)
                except Exception:
                    rendered = False
            rendered = (
                self._set_twin_segment(
                    self.twin_path_lines[index], path[index], path[index + 1]
                )
                and rendered
            )

        axis_origin = (14, self.twin_viewport_height - 14)
        axis_targets = (
            (44, self.twin_viewport_height - 14),
            (14, self.twin_viewport_height - 44),
            (31, self.twin_viewport_height - 34),
        )
        axis_indexes = (
            (0, 1)
            if projection == "top"
            else (0, 2) if projection == "front" else (0, 1, 2)
        )
        for index in axis_indexes:
            rendered = (
                self._set_twin_segment(
                    self.twin_axis_lines[index], axis_origin, axis_targets[index]
                )
                and rendered
            )

        marker_offset = self.twin_joint_size // 2
        for marker, point in zip(self.twin_joint_markers, arm):
            marker.set_pos(point[0] - marker_offset, point[1] - marker_offset)
            marker.remove_flag(self.lv.obj.FLAG.HIDDEN)

        if rendered:
            self.twin_renderer_notice.add_flag(self.lv.obj.FLAG.HIDDEN)
        else:
            self.twin_renderer_notice.set_text("LVGL LINE UPDATE FAILED CLOSED")
            self.twin_renderer_notice.remove_flag(self.lv.obj.FLAG.HIDDEN)
        return rendered

    def _apply_digital_twin(self, view):
        # Reducer-only tests and error-path flows may construct a partial
        # frontend without the digital-twin widget tree.
        if not hasattr(self, "twin_headline"):
            return
        twin = _mapping(_mapping(view).get("digital_twin"))
        if not twin:
            twin = _digital_twin_view({})
        self._last_digital_twin_view = twin
        tone_color = self._tone_color(twin.get("tone"))
        self.twin_headline.set_text(
            _safe_text(twin.get("headline") or "DIGITAL TWIN UNAVAILABLE", 64)
        )
        self.twin_headline.set_style_text_color(self.lv.color_hex(tone_color), 0)
        sample_age = twin.get("sample_age_seconds")
        age_text = "--" if sample_age is None else "%.2f S" % sample_age
        pose_sequence = twin.get("pose_sequence")
        self.twin_pose_detail.set_text(
            "POSE %s | AGE %s | MODEL %s"
            % (
                "--" if pose_sequence is None else str(pose_sequence),
                age_text,
                _safe_text(twin.get("model_digest") or "--", 12),
            )
        )

        gate_rows = twin.get("gate_rows")
        if not isinstance(gate_rows, (list, tuple)) or len(gate_rows) != 8:
            gate_rows = _digital_twin_unavailable()["gate_rows"]
        verified = sum(1 for _name, passed in gate_rows if passed is True)
        self.twin_gate_summary.set_text("%d / 8 VERIFIED" % verified)
        self.twin_gate_summary.set_style_text_color(
            self.lv.color_hex(self.OK if verified == 8 else tone_color),
            0,
        )
        cameras = _mapping(twin.get("cameras"))
        tool = _mapping(cameras.get("tool"))
        workspace = _mapping(cameras.get("workspace"))

        def camera_status(camera):
            age = camera.get("age_seconds")
            if camera.get("depth_ready") is not True or age is None:
                return "BLOCKED"
            return "DEPTH %.2f S" % age

        self.twin_camera_summary.set_text(
            "TOOL %s | WORKSPACE %s" % (camera_status(tool), camera_status(workspace))
        )
        for widget, row in zip(self.twin_gate_rows, gate_rows):
            name, passed = row
            widget.set_text(("OK  " if passed else "--  ") + _safe_text(name, 24))
            widget.set_style_text_color(
                self.lv.color_hex(self.OK if passed else self.WARN),
                0,
            )

        projection = getattr(self, "_twin_projection", "isometric")
        if projection not in ("isometric", "top", "front"):
            projection = "isometric"
            self._twin_projection = projection
        for key, widgets in self.twin_projection_buttons.items():
            selected = key == projection
            color = self.ACCENT if selected else self.BORDER
            self._set_panel_color(widgets["button"], color)
            widgets["button"].set_style_bg_color(
                self.lv.color_hex(self.CARD if selected else self.PANEL),
                0,
            )
            widgets["label"].set_style_text_color(
                self.lv.color_hex(self.ACCENT if selected else self.DIM),
                0,
            )
        render_ok = self._render_digital_twin(twin)
        self._twin_render_ok = render_ok

        system = _system_control_view(view)
        challenge = bool(getattr(self, "_motion_search_challenge", ""))
        latched = bool(getattr(self, "_motion_stop_latched", False))
        pending = bool(getattr(self, "_motion_search_request_pending", False))
        enabled = False
        action = "SEARCH GESPERRT"
        detail = twin.get("detail") or "Keine freigegebene 3D-Trajektorie"
        action_tone = twin.get("tone") or "muted"
        stage = "READ-ONLY TWIN | SEARCH GESPERRT"
        if challenge:
            action = "NOCHMAL BESTAETIGEN"
            detail = "Arbeitsraum frei und physischer Not-Aus erreichbar?"
            action_tone = "warn"
            stage = "READ-ONLY TWIN | 2 / 4  ZWEITE BESTAETIGUNG"
            enabled = not pending
        elif latched or system.get("stop_allowed") is True:
            action = "SOFTWARE STOP"
            detail = "Suchlaufstatus wird verifiziert; STOP bleibt sofort erreichbar"
            action_tone = "danger"
            stage = "READ-ONLY TWIN | 3 / 4  STOP BEREIT"
            enabled = True
        elif system.get("safety_setup_required") is True:
            action = "SAFETY SETUP >"
            detail = "Pinned xArm-Safetyprofil zuerst konfigurieren"
            action_tone = "warn"
            stage = "READ-ONLY TWIN | SAFETY SETUP REQUIRED"
            enabled = not pending
        elif pending:
            action = "BITTE WARTEN"
            detail = "Bestehende Search-Gates werden serverseitig geprueft"
            action_tone = "warn"
            stage = "READ-ONLY TWIN | SAFETY CHECK"
        elif (
            render_ok
            and (
                twin.get("preflight_ready") is True
                or twin.get("admission_ready") is True
            )
            and (
                system.get("search_request_allowed") is True
                or system.get("search_action_allowed") is True
            )
        ):
            action = "SEARCH PATH START"
            detail = "Fester validierter Pfad; Start nur mit 2-Schritt-Freigabe"
            action_tone = "ok" if twin.get("admission_ready") else "warn"
            stage = "READ-ONLY TWIN | 1 / 4  3D GATES BEREIT"
            enabled = True

        action_color = self._tone_color(action_tone)
        self.twin_action_stage.set_text(stage)
        self.twin_action_stage.set_style_text_color(self.lv.color_hex(action_color), 0)
        self.twin_action_detail.set_text(_safe_text(detail, 96))
        self.twin_action_button_label.set_text(action)
        if enabled:
            self.twin_action_button.remove_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.twin_action_button, action_color)
        else:
            self.twin_action_button.add_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.twin_action_button, self.DIM)

    def _render_workspace_teach(self, teach):
        """Render only bounded evidence from the strict workspace snapshot."""

        if not hasattr(self, "workspace_teach_hard_lines"):
            return False
        slots = self.workspace_teach_hard_lines + self.workspace_teach_captured_lines
        for slot in slots:
            self._hide_twin_segment(slot)
        self.workspace_teach_tcp_marker.add_flag(self.lv.obj.FLAG.HIDDEN)
        if teach.get("valid") is not True:
            self.workspace_teach_renderer_notice.set_text(
                "VALIDATED WORKSPACE SNAPSHOT UNAVAILABLE"
            )
            self.workspace_teach_renderer_notice.remove_flag(self.lv.obj.FLAG.HIDDEN)
            return False
        if not getattr(self, "workspace_teach_line_supported", False):
            self.workspace_teach_renderer_notice.set_text(
                "PINNED LVGL LINE RENDERER UNAVAILABLE"
            )
            self.workspace_teach_renderer_notice.remove_flag(self.lv.obj.FLAG.HIDDEN)
            return False
        geometry = _project_workspace_teach_geometry(
            teach,
            self.workspace_teach_viewport_width,
            self.workspace_teach_viewport_height,
        )
        if geometry.get("valid") is not True:
            self.workspace_teach_renderer_notice.set_text(
                "WORKSPACE PROJECTION FAILED CLOSED"
            )
            self.workspace_teach_renderer_notice.remove_flag(self.lv.obj.FLAG.HIDDEN)
            return False
        rendered = True
        for slot, edge in zip(
            self.workspace_teach_hard_lines,
            geometry.get("hard_edges") or (),
        ):
            rendered = self._set_twin_segment(slot, edge[0], edge[1]) and rendered
        captured_edges = []
        for _step, face in geometry.get("captured_faces") or ():
            captured_edges.extend(face)
        for slot, edge in zip(self.workspace_teach_captured_lines, captured_edges):
            rendered = self._set_twin_segment(slot, edge[0], edge[1]) and rendered
        tcp = geometry.get("tcp")
        if tcp is not None:
            offset = self.workspace_teach_tcp_size // 2
            self.workspace_teach_tcp_marker.set_pos(
                tcp[0] - offset,
                tcp[1] - offset,
            )
            self.workspace_teach_tcp_marker.remove_flag(self.lv.obj.FLAG.HIDDEN)
        if rendered:
            self.workspace_teach_renderer_notice.add_flag(self.lv.obj.FLAG.HIDDEN)
        else:
            self.workspace_teach_renderer_notice.set_text(
                "LVGL LINE UPDATE FAILED CLOSED"
            )
            self.workspace_teach_renderer_notice.remove_flag(self.lv.obj.FLAG.HIDDEN)
        return rendered

    def _apply_workspace_teach(self, view):
        """Apply health authority and never promote an HTTP reply to success."""

        teach = _mapping(_mapping(view).get("workspace_teach"))
        if not teach:
            teach = _workspace_teach_view({})
        boundary = _mapping(_mapping(view).get("workspace_boundary"))
        if not boundary:
            boundary = _workspace_boundary_view({})
        previous = _mapping(getattr(self, "_last_workspace_teach_view", {}))
        waiting = _mapping(getattr(self, "_workspace_teach_waiting", {}))
        if waiting and teach.get("valid") is True:
            operation = waiting.get("operation")
            same_session = teach.get("session_id") == waiting.get("session_id")
            matched = False
            if operation == "workspace_teach_start":
                matched = bool(
                    teach.get("state")
                    in ("awaiting_teach", "positioning", "ready_to_capture")
                    and _lower_hex(teach.get("session_id"), 32)
                )
            elif operation == "workspace_teach_capture":
                matched = bool(
                    same_session
                    and isinstance(teach.get("completed_steps"), int)
                    and teach.get("completed_steps")
                    > int(waiting.get("completed_steps") or 0)
                )
            elif operation == "workspace_teach_cancel":
                matched = bool(same_session and teach.get("state") == "cancelled")
            elif operation == "workspace_teach_finalize":
                matched = bool(
                    same_session
                    and teach.get("state") == "proposed"
                    and teach.get("proposal_sha256") == waiting.get("proposal_sha256")
                )
            correlation_failed = bool(
                operation == "workspace_teach_finalize"
                and teach.get("state") == "proposed"
                and not matched
            )
            # A terminal invalidation or a changed session is authoritative,
            # but is never rendered as action success.
            abandoned = (
                bool(
                    teach.get("state") == "invalidated"
                    or (
                        operation != "workspace_teach_start"
                        and _lower_hex(teach.get("session_id"), 32)
                        and not same_session
                    )
                )
                and not correlation_failed
            )
            if matched or abandoned:
                self._workspace_teach_waiting = {}
                self._workspace_teach_request_pending = False
            elif correlation_failed:
                # Do not render `proposed` from an unrelated session/digest as
                # completion of the in-flight finalize. Keep the last review
                # visible and wait for an exactly correlated health sample.
                teach = dict(previous)
                teach.update(
                    {
                        "tone": "danger",
                        "headline": "PROPOSAL HEALTH NICHT KORRELIERT",
                        "detail": "Passende Session und Proposal-SHA256 abwarten",
                        "status": "CHECK",
                    }
                )

        if getattr(self, "_workspace_teach_finalize_challenge", ""):
            if not self._workspace_teach_confirmation_current(teach):
                self._clear_workspace_teach_finalize_challenge()
        if teach.get("state") not in ("idle", "cancelled"):
            self._workspace_teach_notice_acknowledged = False
        elif previous.get("state") != teach.get("state"):
            self._workspace_teach_notice_acknowledged = False
        self._last_workspace_teach_view = teach

        # Reducer/flow tests may intentionally omit the widget tree.
        if not hasattr(self, "workspace_teach_headline"):
            return teach
        tone_color = self._tone_color(teach.get("tone") or "muted")
        self.workspace_teach_headline.set_text(
            _safe_text(teach.get("headline") or "WORKSPACE TEACH UNAVAILABLE", 64)
        )
        self.workspace_teach_headline.set_style_text_color(
            self.lv.color_hex(tone_color), 0
        )
        self.workspace_teach_progress.set_text(
            "%d / 6 GRENZEN | FRAME %s"
            % (
                int(teach.get("completed_steps") or 0),
                _safe_text(teach.get("coordinate_frame") or "--", 24),
            )
        )
        guidance = _mapping(teach.get("guidance"))
        mode_blocked = teach.get("mode_two_blocked") is True
        self.workspace_teach_mode.set_text(
            "MODE 2 EXTERN AKTIVIEREN"
            if mode_blocked
            else "CONTROLLER MODE 2 EXTERN PRUEFEN"
        )
        self.workspace_teach_mode.set_style_text_color(
            self.lv.color_hex(self.WARN if mode_blocked else self.MUTED), 0
        )
        self.workspace_teach_guidance_title.set_text(
            _safe_text(
                guidance.get("title") or teach.get("headline") or "UNAVAILABLE",
                48,
            )
        )
        self.workspace_teach_guidance_detail.set_text(
            _safe_text(
                guidance.get("instruction")
                or teach.get("detail")
                or "Health-Snapshot abwarten",
                96,
            )
        )
        completed = int(teach.get("completed_steps") or 0)
        current_step = teach.get("current_step")
        for index, (step, widget) in enumerate(
            zip(_WORKSPACE_TEACH_STEPS, self.workspace_teach_step_rows)
        ):
            prefix = (
                "OK" if index < completed else (">>" if step == current_step else "--")
            )
            widget.set_text("%s  %s" % (prefix, step.upper()))
            widget.set_style_text_color(
                self.lv.color_hex(
                    self.OK
                    if index < completed
                    else self.WARN if step == current_step else self.DIM
                ),
                0,
            )
        digest = teach.get("proposal_sha256") or ""
        self.workspace_teach_digest.set_text(
            "PROPOSAL SHA256 %s" % (digest[:16] if digest else "--")
        )
        render_ok = self._render_workspace_teach(teach)
        self._workspace_teach_render_ok = render_ok

        pending = bool(getattr(self, "_workspace_teach_request_pending", False))
        state = teach.get("state")
        primary_enabled = False
        primary_label = "NICHT FREIGEGEBEN"
        detail = "Health-Snapshot ist die alleinige Zustandsquelle"
        primary_tone = "muted"
        if pending:
            primary_label = "HEALTH-SNAPSHOT ABWARTEN"
            detail = "Aktion uebertragen; Erfolg wird erst aus Health angezeigt"
            primary_tone = "warn"
        elif state in ("idle", "cancelled") and render_ok:
            if getattr(self, "_workspace_teach_notice_acknowledged", False):
                primary_label = "SESSION STARTEN"
                detail = (
                    "Start sendet keine Koordinaten und aendert keinen Controller-Modus"
                )
            else:
                primary_label = "SICHERHEITSHINWEIS LESEN"
                detail = _WORKSPACE_TEACH_SAFETY_NOTICE
            primary_enabled = True
            primary_tone = "warn"
        elif state in ("awaiting_teach", "positioning"):
            primary_label = (
                "MODE 2 EXTERN AKTIVIEREN"
                if mode_blocked
                else "TCP VON HAND POSITIONIEREN"
            )
            detail = guidance.get("instruction") or teach.get("detail") or ""
            primary_tone = "warn"
        elif state == "ready_to_capture":
            primary_label = "POSITION ERFASSEN"
            primary_enabled = bool(
                render_ok
                and teach.get("pose_ready") is True
                and not teach.get("blockers")
                and not mode_blocked
            )
            detail = "Nur aktuelle Backend-TCP-Pose; keine UI-Koordinaten"
            primary_tone = "ok"
        elif state == "review":
            primary_label = "VORSCHLAG FINALISIEREN"
            primary_enabled = bool(
                render_ok
                and _lower_hex(teach.get("proposal_sha256"), 64)
                and _lower_hex(teach.get("session_id"), 32)
            )
            detail = "Ein Klick fuehrt beide servergebundenen Finalisierungsphasen aus"
            primary_tone = "warn"
        elif state == "proposed":
            boundary_correlated = bool(
                boundary.get("session_id") == teach.get("session_id")
                and boundary.get("proposal_sha256") == teach.get("proposal_sha256")
            )
            if boundary_correlated and boundary.get("state") == "validating":
                primary_label = "2x OAK + NEWTON PRUEFEN"
                detail = "Sechs TCP-Grenzposen werden lokal und fail-closed validiert"
                primary_tone = "warn"
            elif boundary_correlated and boundary.get("state") == "valid":
                primary_label = "APP-ARBEITSRAUM GUELTIG"
                detail = "TCP-Box, beide Kameras und gepinntes Newton-Modell korreliert"
                primary_tone = "ok"
            elif boundary_correlated and boundary.get("state") in (
                "blocked",
                "invalidated",
            ):
                primary_label = "ARBEITSRAUM-PRUEFUNG BLOCKIERT"
                detail = boundary.get("detail") or "Neue Einmessung erforderlich"
                primary_tone = "danger"
            elif boundary.get("configured") is True:
                primary_label = "ARBEITSRAUM-PRUEFUNG ABWARTEN"
                detail = "Passende Session und Proposal-SHA256 fehlen"
                primary_tone = "warn"
            else:
                primary_label = "PRUEFVORSCHLAG GESPEICHERT"
                detail = (
                    "Read-only; keine Motion-Freigabe und kein Boundary-Schreibbefehl"
                )
                primary_tone = "ok"
        elif state == "invalidated":
            primary_label = "SESSION UNGUELTIG"
            detail = teach.get("detail") or "Session verwerfen und neu beginnen"
            primary_tone = "danger"

        self.workspace_teach_action_detail.set_text(_safe_text(detail, 96))
        self.workspace_teach_primary_label.set_text(primary_label)
        if primary_enabled:
            self.workspace_teach_primary_button.remove_state(self.lv.STATE.DISABLED)
            self._set_panel_color(
                self.workspace_teach_primary_button,
                self._tone_color(primary_tone),
            )
        else:
            self.workspace_teach_primary_button.add_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.workspace_teach_primary_button, self.DIM)

        cancel_enabled = bool(
            not pending
            and teach.get("valid") is True
            and state
            in (
                "awaiting_teach",
                "positioning",
                "ready_to_capture",
                "review",
                "invalidated",
            )
        )
        if cancel_enabled:
            self.workspace_teach_cancel_button.remove_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.workspace_teach_cancel_button, self.WARN)
        else:
            self.workspace_teach_cancel_button.add_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.workspace_teach_cancel_button, self.DIM)
        return teach

    def _apply_tenant_auth(self, view):
        """Render only the secret-free, tenant-bound health projection."""

        auth = _mapping(_mapping(view).get("tenant_auth"))
        if not auth:
            auth = _mapping(getattr(self, "_last_tenant_auth_view", {}))
        if not auth:
            auth = _tenant_auth_view({})

        pending = bool(getattr(self, "_tenant_auth_request_pending", False))
        waiting = _mapping(getattr(self, "_tenant_auth_waiting", {}))
        local_status = _safe_text(
            getattr(self, "_tenant_auth_local_status", ""),
            64,
        )
        state = auth.get("state")
        login_correlated = bool(
            waiting.get("operation") == "tenant_login"
            and state in ("authenticated", "refresh_required")
            and auth.get("tenant_url") == waiting.get("tenant_url")
            and auth.get("tenant") == waiting.get("tenant")
            and auth.get("username") == waiting.get("username")
        )
        logout_correlated = bool(
            waiting.get("operation") == "tenant_logout" and state == "logged_out"
        )
        login_mismatch = bool(
            waiting.get("operation") == "tenant_login"
            and state in ("authenticated", "refresh_required")
            and not login_correlated
        )
        if login_correlated or logout_correlated:
            pending = False
            self._tenant_auth_request_pending = False
            self._tenant_auth_local_status = ""
            self._tenant_auth_waiting = {}
            local_status = ""
        elif login_mismatch:
            pending = False
            self._tenant_auth_request_pending = False
            self._tenant_auth_local_status = "session_mismatch"
            self._tenant_auth_waiting = {}
            local_status = "session_mismatch"
        self._last_tenant_auth_view = dict(auth)

        # Reducer/flow tests intentionally construct no widget tree.
        if not hasattr(self, "tenant_auth_headline"):
            return auth

        headline = "TENANT LOGIN"
        detail = "Tenant-Domain, Benutzername und Passwort eingeben"
        tone = auth.get("tone") or "muted"
        if pending or local_status in (
            "signing_in",
            "signing_out",
            "awaiting_health",
        ):
            headline = "ANFRAGE WIRD VERARBEITET"
            detail = "Serverseitigen Session-Status abwarten"
            tone = "warn"
        elif local_status and local_status not in ("authenticated", "logged_out"):
            headline = "LOGIN NICHT ABGESCHLOSSEN"
            detail = local_status.replace("_", " ").upper()
            tone = "danger" if local_status != "tenant_unavailable" else "warn"
        elif state in ("authenticated", "refresh_required"):
            registration = _mapping(
                getattr(self, "_tenant_device_registration", {})
            )
            if registration.get("token"):
                mail_state = (
                    "MAIL %s" % _safe_text(
                        registration.get("email_recipient") or "SENT", 32
                    )
                    if registration.get("email_sent") is True
                    else "MAIL NOT SENT"
                )
                headline = "DEVICE %s TOKEN | %s" % (
                    _safe_text(registration.get("uid_device") or "--", 28),
                    mail_state,
                )
                detail = _safe_text(registration.get("token"), 128)
                tone = "ok"
            else:
                headline = "ANGEMELDET: %s" % _safe_text(
                    auth.get("display_name") or auth.get("username") or "--",
                    40,
                )
                detail = "%s | %s" % (
                    _safe_text(auth.get("tenant") or "--", 48),
                    _safe_text(auth.get("tenant_url") or "--", 80),
                )
        elif state == "expired":
            headline = "SESSION ABGELAUFEN"
            detail = "Erneut mit dem Tenant anmelden"
            tone = "warn"
        elif state == "error":
            headline = "TENANT SESSION PRUEFEN"
            detail = _safe_text(auth.get("last_error") or "LOGIN FEHLER", 64)
            tone = "danger"
        elif state == "unavailable":
            headline = "TENANT LOGIN UNAVAILABLE"
            detail = "Lokalen Gateway-Login pruefen"

        color = self._tone_color(tone)
        self.tenant_auth_headline.set_text(_safe_text(headline, 64))
        self.tenant_auth_headline.set_style_text_color(self.lv.color_hex(color), 0)
        self.tenant_auth_detail.set_text(_safe_text(detail, 128))

        signed_in = state in ("authenticated", "refresh_required")
        input_supported = bool(getattr(self, "tenant_auth_input_supported", False))
        login_enabled = bool(input_supported and not signed_in and not pending)
        logout_enabled = bool(signed_in and not pending)
        if login_enabled:
            self.tenant_auth_login_button.remove_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.tenant_auth_login_button, self.OK)
        else:
            self.tenant_auth_login_button.add_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.tenant_auth_login_button, self.DIM)
        self.tenant_auth_login_label.set_text("BITTE WARTEN" if pending else "ANMELDEN")
        if logout_enabled:
            self.tenant_auth_logout_button.remove_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.tenant_auth_logout_button, self.WARN)
        else:
            self.tenant_auth_logout_button.add_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.tenant_auth_logout_button, self.DIM)

        for field in (
            getattr(self, "tenant_auth_tenant_input", None),
            getattr(self, "tenant_auth_username_input", None),
            getattr(self, "tenant_auth_password_input", None),
        ):
            if field is None:
                continue
            if signed_in or pending:
                field.add_state(self.lv.STATE.DISABLED)
            else:
                field.remove_state(self.lv.STATE.DISABLED)
        return auth

    def _apply_system(self, view):
        system = _system_control_view(view)
        search = self._last_motion_search_view
        runtime_role = _runtime_role_view(view)
        self.system_xarm_eyebrow.set_text("xARM CONTROLLER / %s" % runtime_role["role"])
        xarm_color = self._tone_color(system["xarm_tone"])
        self.system_xarm_headline.set_text(system["xarm_headline"])
        self.system_xarm_headline.set_style_text_color(self.lv.color_hex(xarm_color), 0)
        self.system_xarm_detail.set_text(system["xarm_detail"])
        self.system_xarm_guidance.set_text(system["xarm_guidance"])
        self.system_xarm_guidance.set_style_text_color(self.lv.color_hex(xarm_color), 0)
        self.system_search_review.set_text(
            _safe_text(search.get("review") or system["search_review"], 96)
        )

        motion_color = self._tone_color(system["motion_tone"])
        self.system_motion_gate.set_text(system["motion_gate"])
        self.system_motion_gate.set_style_text_color(self.lv.color_hex(motion_color), 0)
        self.system_motion_detail.set_text(system["motion_detail"])

        capture_color = self._tone_color(system["capture_tone"])
        self.system_capture_gate.set_text(system["capture_gate"])
        self.system_capture_gate.set_style_text_color(
            self.lv.color_hex(capture_color), 0
        )
        self.system_capture_detail.set_text(system["capture_detail"])

        action = dict(system)
        progress = int(search.get("workflow_progress") or 0)
        progress = min(max(progress, 0), 100)
        stage = _safe_text(
            search.get("workflow_stage") or system["search_stage"],
            48,
        )
        if self._motion_search_challenge:
            action.update(
                {
                    "action": "NOCHMAL BESTAETIGEN",
                    "action_detail": "Arbeitsraum frei und physischer Not-Aus erreichbar?",
                    "action_tone": "warn",
                    "search_action_allowed": True,
                    "search_request_allowed": True,
                }
            )
            progress = 50
            stage = "2 / 4  ZWEITE BESTAETIGUNG"
        elif self._motion_stop_latched:
            action.update(
                {
                    "action": "SOFTWARE STOP",
                    "action_detail": (
                        search.get("detail")
                        if search.get("request_result")
                        not in ("", "accepted", "checking", "confirm")
                        else "Bewegungsstatus wird verifiziert; STOP bleibt aktiv"
                    ),
                    "action_tone": "danger",
                    "stop_allowed": True,
                }
            )
            progress = max(progress, 75)
            if search.get("request_result") in (
                "confirmation_required",
                "busy",
                "unsafe",
                "unavailable",
                "error",
            ):
                stage = _safe_text(search.get("workflow_stage"), 48)
            else:
                stage = "3 / 4  SUCHLAUF / STOP-PRUEFUNG"
        elif search.get("request_result"):
            action.update(
                {
                    "action": search.get("button") or action["action"],
                    "action_detail": search.get("detail") or action["action_detail"],
                    "action_tone": search.get("tone") or action["action_tone"],
                    "search_request_allowed": (search.get("request_allowed") is True),
                }
            )
        stage_color = self._tone_color(action["action_tone"])
        self.system_search_stage.set_text("ROBOTER-STEUERUNG  |  %s" % stage)
        self.system_search_stage.set_style_text_color(self.lv.color_hex(stage_color), 0)
        progress_width = max(
            1,
            int(self.system_search_progress_width * progress / 100),
        )
        self.system_search_progress_fill.set_size(
            progress_width,
            self.system_search_progress_height,
        )
        self._set_panel_color(self.system_search_progress_fill, stage_color)
        self.system_run_button_label.set_text(action["action"])
        self.system_run_detail.set_text(action["action_detail"])
        enabled = bool(
            not self._motion_search_request_pending
            and (
                action.get("safety_setup_required") is True
                or action.get("search_action_allowed") is True
                or action.get("search_request_allowed") is True
                or bool(self._motion_search_challenge)
                or action.get("stop_allowed") is True
            )
        )
        if enabled:
            self.system_run_button.remove_state(self.lv.STATE.DISABLED)
            self._set_panel_color(
                self.system_run_button,
                self._tone_color(action["action_tone"]),
            )
        else:
            self.system_run_button.add_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.system_run_button, self.DIM)

        stop_enabled = not self._software_stop_request_pending
        if stop_enabled:
            self.system_stop_button.remove_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.system_stop_button, self.DANGER)
            self.system_stop_button_label.set_style_text_color(
                self.lv.color_hex(self.INK), 0
            )
        else:
            # Keep STOP permanently visible on the robot-control page.  The
            # disabled red outline communicates where it will become active
            # without allowing an idle click to masquerade as a robot action.
            self.system_stop_button.add_state(self.lv.STATE.DISABLED)
            self.system_stop_button.set_style_bg_color(self.lv.color_hex(self.CARD), 0)
            self.system_stop_button.set_style_border_color(
                self.lv.color_hex(self.DANGER), 0
            )
            self.system_stop_button.set_style_border_width(2, 0)
            self.system_stop_button_label.set_style_text_color(
                self.lv.color_hex(self.DANGER), 0
            )

    def _apply_robot_metrics(self, view):
        dashboard = _robot_metrics_view(view)
        count = int(dashboard.get("page_count") or 4)
        if count != 4:
            count = 4
        page_index = int(getattr(self, "_robot_metrics_page_index", 0)) % count
        self._robot_metrics_page_index = page_index
        page = dashboard["pages"][page_index]
        self.system_metrics_page_title.set_text(page["title"])
        self.system_metrics_page_number.set_text(
            "PAGE %d / %d" % (page_index + 1, count)
        )
        fresh = dashboard.get("valid") is True and dashboard.get("fresh") is True
        freshness_tone = "ok" if fresh else "warn"
        freshness_color = self._tone_color(freshness_tone)
        self.system_metrics_fresh_label.set_text(
            "TELEMETRY LIVE" if fresh else "TELEMETRY STALE"
        )
        self.system_metrics_fresh_label.set_style_text_color(
            self.lv.color_hex(freshness_color), 0
        )
        self.system_metrics_fresh_badge.set_style_border_color(
            self.lv.color_hex(freshness_color), 0
        )
        metrics = page.get("metrics") or []
        for index, widgets in enumerate(self.system_metrics_rows):
            if index < len(metrics):
                metric = metrics[index]
                tone_color = self._tone_color(metric["tone"])
                widgets["label"].set_text(metric["label"])
                widgets["value"].set_text(metric["value"])
                widgets["value"].set_style_text_color(self.lv.color_hex(tone_color), 0)
                widgets["panel"].set_style_border_color(
                    self.lv.color_hex(tone_color), 0
                )
                widgets["panel"].remove_flag(self.lv.obj.FLAG.HIDDEN)
            else:
                widgets["panel"].add_flag(self.lv.obj.FLAG.HIDDEN)

    def _apply_safety_configuration(self, view):
        authoritative = _safety_configuration_view(view)
        boundary = _mapping(_mapping(view).get("workspace_boundary"))
        if not boundary:
            boundary = _workspace_boundary_view({})
        # A local confirmation/status message remains visible only until the
        # next authoritative exact readback arrives. It never grants Search.
        safety = authoritative
        pending = getattr(self, "_last_safety_configuration_view", {})
        if (
            getattr(self, "_safety_configuration_request_pending", False)
            or getattr(self, "_safety_configuration_challenge", "")
            or getattr(self, "_safety_configuration_local_pending", False)
        ):
            safety = pending
        else:
            self._last_safety_configuration_view = authoritative
        color = self._tone_color(safety.get("tone") or "muted")
        self.safety_headline.set_text(safety.get("headline") or "UNAVAILABLE")
        self.safety_headline.set_style_text_color(self.lv.color_hex(color), 0)
        self.safety_detail.set_text(safety.get("detail") or "")
        self.safety_digest.set_text(
            "SHA256 %s" % (safety.get("profile_sha256") or "--")
        )
        for index, widgets in enumerate(self.safety_profile_rows):
            rows = safety.get("profile_rows") or ()
            if index < len(rows):
                widgets["label"].set_text(rows[index][0])
                widgets["value"].set_text(rows[index][1])
                widgets["value"].set_style_text_color(self.lv.color_hex(color), 0)
                widgets["panel"].remove_flag(self.lv.obj.FLAG.HIDDEN)
            else:
                widgets["panel"].add_flag(self.lv.obj.FLAG.HIDDEN)
        preflight = safety.get("preflight_rows") or ()
        for index, label in enumerate(self.safety_preflight_labels):
            if index < len(preflight):
                name, result = preflight[index]
                label.set_text("%s: %s" % (name, result))
                gate_color = self.OK if result == "OK" else self.DANGER
                label.set_style_text_color(self.lv.color_hex(gate_color), 0)
            else:
                label.set_text("--")
                label.set_style_text_color(self.lv.color_hex(self.MUTED), 0)
        remaining = safety.get("remaining_gates") or ()
        for index, label in enumerate(self.safety_remaining_labels):
            if index < len(remaining):
                label.set_text("- %s" % remaining[index])
                label.set_style_text_color(self.lv.color_hex(self.WARN), 0)
            else:
                label.set_text("--" if index == 0 else "")
                label.set_style_text_color(
                    self.lv.color_hex(
                        self.OK if safety.get("search_ready") else self.DIM
                    ),
                    0,
                )
        self.safety_config_button_label.set_text(safety.get("button") or "BLOCKED")
        enabled = bool(
            not getattr(self, "_safety_configuration_request_pending", False)
            and (
                safety.get("action_allowed") is True
                or safety.get("search_ready") is True
            )
        )
        if enabled:
            self.safety_config_button.remove_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.safety_config_button, color)
        else:
            self.safety_config_button.add_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.safety_config_button, self.DIM)

        boundary_state = boundary.get("state")
        boundary_tone = boundary.get("tone") or "muted"
        if boundary_state == "valid":
            boundary_label = "ARBEITSRAUM GUELTIG"
        elif boundary_state == "validating":
            boundary_label = "2x OAK + NEWTON..."
        elif boundary_state in ("blocked", "invalidated"):
            boundary_label = "ARBEITSRAUM NEU EINMESSEN"
        else:
            boundary_label = "ARBEITSRAUM EINMESSEN"
        self.workspace_boundary_setup_label.set_text(boundary_label)
        self._set_panel_color(
            self.workspace_boundary_setup_button,
            self._tone_color(boundary_tone),
        )

        # Permanent, idempotent STOP remains available even if health is stale.
        stop_active = not self._software_stop_request_pending
        if stop_active:
            self.safety_stop_button.remove_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.safety_stop_button, self.DANGER)
        else:
            self.safety_stop_button.add_state(self.lv.STATE.DISABLED)
            self.safety_stop_button.set_style_bg_color(self.lv.color_hex(self.CARD), 0)
            self.safety_stop_button.set_style_border_color(
                self.lv.color_hex(self.DANGER), 0
            )

    def _apply_software_stop_nav(self, capture):
        # Unit/headless construction can exercise action and resize logic
        # before the widget tree exists.  The safety state is owned by the
        # latch, not by this optional rendering target.
        software_stop_nav = getattr(self, "software_stop_nav", None)
        if software_stop_nav is None:
            return
        # The global control is always present.  A click is safe while idle
        # because the backend STOP endpoint is explicitly idempotent.
        software_stop_nav.remove_flag(self.lv.obj.FLAG.HIDDEN)

    def _apply_camera_page(self, role, camera):
        widgets = self.camera_page_widgets[role]
        color = self._tone_color(camera["tone"])
        widgets["headline"].set_text(camera["headline"])
        widgets["headline"].set_style_text_color(self.lv.color_hex(color), 0)
        widgets["detail"].set_text(camera["detail"])
        widgets["metadata"].set_text(
            "ROLE %s | BACKEND %s | %s %s\nAGE %s | SEQ %s | RECONNECT %s | ERR %s"
            % (
                _safe_text(camera.get("role") or role, 16).upper(),
                _safe_text(camera.get("backend") or "UNKNOWN", 16),
                _safe_text(camera.get("identity_kind") or "ID", 8),
                _safe_text(camera.get("identity") or "--", 40),
                _safe_text(camera.get("age") or "--", 10),
                _safe_text(camera.get("sequence") or "--", 12),
                _safe_text(camera.get("reconnects") or "--", 12),
                _safe_text(camera.get("errors") or "--", 12),
            )
        )
        widgets["preview"].set_style_border_color(self.lv.color_hex(color), 0)

    def _drop_retired_image_cache(self, descriptor):
        """Drop only a source that has survived two later generations."""

        drop = getattr(self.lv, "image_cache_drop", None)
        if not callable(drop):
            return
        try:
            drop(descriptor)
        except Exception:
            # Some LVGL MicroPython revisions do not export cache eviction, or
            # accept only particular source kinds.  Strong-reference retirement
            # remains the safety boundary in either case.
            pass

    def _retire_image_generation(self, generations, jpeg, descriptor):
        if not isinstance(generations, list):
            return
        if not isinstance(jpeg, bytes) or descriptor is None:
            return
        generations.append((jpeg, descriptor))
        while len(generations) > 2:
            _old_jpeg, old_descriptor = generations.pop(0)
            self._drop_retired_image_cache(old_descriptor)

    def _clear_camera_preview_source(self, role):
        preview_bytes = getattr(self, "_preview_bytes", {})
        descriptors = getattr(self, "_preview_descriptors", {})
        if not isinstance(preview_bytes, dict):
            preview_bytes = {}
            self._preview_bytes = preview_bytes
        if not isinstance(descriptors, dict):
            descriptors = {}
            self._preview_descriptors = descriptors
        retired = getattr(self, "_preview_retired", None)
        if not isinstance(retired, dict):
            retired = {}
            self._preview_retired = retired
        generations = retired.setdefault(role, [])
        self._retire_image_generation(
            generations,
            preview_bytes.get(role),
            descriptors.get(role),
        )
        preview_bytes[role] = None
        descriptors[role] = None

    def _clear_manual_review_preview_source(self):
        retired = getattr(self, "_manual_review_preview_retired", None)
        if not isinstance(retired, list):
            retired = []
            self._manual_review_preview_retired = retired
        self._retire_image_generation(
            retired,
            getattr(self, "_manual_review_preview_bytes", None),
            getattr(self, "_manual_review_preview_descriptor", None),
        )
        self._manual_review_preview_bytes = None
        self._manual_review_preview_descriptor = None

    def _show_camera_preview_error(self, role, detail):
        widgets = self.camera_page_widgets.get(role)
        if widgets is None:
            return
        widgets["image"].add_flag(self.lv.obj.FLAG.HIDDEN)
        widgets["preview_label"].set_text(
            "LIVE PREVIEW UNAVAILABLE\n\n%s\n\nNOT SAVED TO DATASET"
            % _safe_text(detail or "Snapshot failed", 64)
        )
        widgets["preview_label"].set_style_text_color(self.lv.color_hex(self.DANGER), 0)
        widgets["preview_label"].remove_flag(self.lv.obj.FLAG.HIDDEN)
        widgets["preview"].set_style_border_color(self.lv.color_hex(self.DANGER), 0)
        self._clear_camera_preview_source(role)

    def _apply_preview_jpeg(self, role, jpeg):
        """Install one validated JPEG while retaining its backing objects."""

        dimensions = _baseline_jpeg_dimensions(jpeg)
        if role not in self.camera_page_widgets or dimensions is None:
            return False
        lv = self.lv
        initialize_decoder = getattr(lv, "tjpgd_init", None)
        if not callable(initialize_decoder):
            return False
        # The decoder registration is idempotent in the pinned LVGL build.  It
        # is kept here so unit construction never depends on camera presence.
        if not getattr(self, "_jpeg_decoder_initialized", False):
            initialize_decoder()
            self._jpeg_decoder_initialized = True
        descriptor = lv.image_dsc_t(
            {
                "header": {
                    "cf": lv.COLOR_FORMAT.RAW,
                    "w": dimensions[0],
                    "h": dimensions[1],
                },
                "data_size": len(jpeg),
                "data": jpeg,
            }
        )
        widgets = self.camera_page_widgets[role]
        retired = getattr(self, "_preview_retired", None)
        if not isinstance(retired, dict):
            retired = {}
            self._preview_retired = retired
        old_jpeg = self._preview_bytes.get(role)
        old_descriptor = self._preview_descriptors.get(role)
        widgets["image"].set_src(descriptor)
        # The C widget stores a pointer into the MicroPython wrapper.  Retain
        # both the wrapper and its JPEG bytes immediately after swapping the
        # source, then keep two older generations alive for deferred decoder
        # and redraw work.
        self._preview_bytes[role] = jpeg
        self._preview_descriptors[role] = descriptor
        self._retire_image_generation(
            retired.setdefault(role, []),
            old_jpeg,
            old_descriptor,
        )
        scale = min(
            widgets["preview_width"] / float(dimensions[0]),
            widgets["preview_height"] / float(dimensions[1]),
        )
        # LVGL's scale units use 256 as 1x.  The official TJPGD decoder cannot
        # transform JPEGs itself, so leave baseline camera frames at native
        # scale and clip them inside the volatile preview card.
        if scale >= 1.0:
            widgets["image"].set_scale(int(scale * 256))
        else:
            widgets["image"].set_scale(256)
        widgets["image"].align(lv.ALIGN.CENTER, 0, 0)
        widgets["image"].remove_flag(lv.obj.FLAG.HIDDEN)
        widgets["preview_label"].add_flag(lv.obj.FLAG.HIDDEN)
        return True

    def _apply_manual_review_preview_jpeg(self, jpeg):
        """Show one challenge-bound review image on the evidence page."""

        dimensions = _baseline_jpeg_dimensions(jpeg)
        image = getattr(self, "manual_review_image", None)
        if dimensions is None or image is None:
            return False
        lv = self.lv
        initialize_decoder = getattr(lv, "tjpgd_init", None)
        if not callable(initialize_decoder):
            return False
        if not getattr(self, "_jpeg_decoder_initialized", False):
            initialize_decoder()
            self._jpeg_decoder_initialized = True
        # The backend emits a bounded JPEG that already fits this page.  The
        # pinned TJPGD decoder cannot downscale JPEGs, so reject a larger frame
        # instead of silently clipping the visual evidence.
        if (
            dimensions[0] > self.manual_review_preview_width
            or dimensions[1] > self.manual_review_preview_height
        ):
            return False
        descriptor = lv.image_dsc_t(
            {
                "header": {
                    "cf": lv.COLOR_FORMAT.RAW,
                    "w": dimensions[0],
                    "h": dimensions[1],
                },
                "data_size": len(jpeg),
                "data": jpeg,
            }
        )
        old_jpeg = getattr(self, "_manual_review_preview_bytes", None)
        old_descriptor = getattr(self, "_manual_review_preview_descriptor", None)
        image.set_src(descriptor)
        self._manual_review_preview_bytes = jpeg
        self._manual_review_preview_descriptor = descriptor
        retired = getattr(self, "_manual_review_preview_retired", None)
        if not isinstance(retired, list):
            retired = []
            self._manual_review_preview_retired = retired
        self._retire_image_generation(retired, old_jpeg, old_descriptor)
        image.set_scale(256)
        image.align(lv.ALIGN.CENTER, 0, 0)
        image.remove_flag(lv.obj.FLAG.HIDDEN)
        self.manual_review_preview_label.add_flag(self.lv.obj.FLAG.HIDDEN)
        return True

    def _apply_manual_review_page(self):
        candidate = _mapping(getattr(self, "_manual_review_candidate", {}))
        candidate_id = _safe_text(candidate.get("observation_id") or "--", 32)
        plate_id = _safe_text(candidate.get("plate_id") or "--", 28)
        cluster_id = _safe_text(candidate.get("cluster_id") or "--", 28)
        confidence = candidate.get("confidence")
        if isinstance(confidence, bool) or not isinstance(confidence, (int, float)):
            confidence_text = "--"
        else:
            confidence_text = "%d %%" % int(max(0, min(1, confidence)) * 100)
        label = getattr(self, "manual_review_candidate_label", None)
        if label is not None:
            label.set_text(
                "ID %s\nPLATE %s\nCLUSTER %s\nCONF %s"
                % (candidate_id, plate_id, cluster_id, confidence_text)
            )
        ready = bool(
            _lower_hex(getattr(self, "_manual_review_challenge", ""), 32)
            and getattr(self, "_manual_review_preview_ready", False)
            and _valid_manual_review_candidate(candidate)
        )
        button = getattr(self, "manual_review_confirm_button", None)
        button_label = getattr(self, "manual_review_confirm_label", None)
        if button is not None and button_label is not None:
            button_label.set_text("AUSWAHL BESTAETIGEN" if ready else "GESPERRT")
            if ready and not self._operations_request_pending:
                button.remove_state(self.lv.STATE.DISABLED)
                self._set_panel_color(button, self.WARN)
            else:
                button.add_state(self.lv.STATE.DISABLED)
                self._set_panel_color(button, self.DIM)
        jpeg = getattr(self, "_manual_review_preview_bytes", None)
        if ready and isinstance(jpeg, bytes):
            self._apply_manual_review_preview_jpeg(jpeg)
        else:
            image = getattr(self, "manual_review_image", None)
            preview_label = getattr(self, "manual_review_preview_label", None)
            if image is not None:
                image.add_flag(self.lv.obj.FLAG.HIDDEN)
            if preview_label is not None:
                preview_label.remove_flag(self.lv.obj.FLAG.HIDDEN)

    def refresh_preview(self, _timer=None):
        # Camera pixels are volatile preview only.  Fetch nothing while another
        # page or the local black screensaver is visible, and never call
        # capture/DataHub from this timer.
        if getattr(self, "_screensaver_active", False):
            return
        role = self._active_view
        if role not in ("tool", "workspace"):
            return
        layout_generation = int(getattr(self, "_layout_generation", 0))

        def apply(response, error):
            # Dropping a result after navigation also prevents an older tool
            # frame from replacing the visible workspace frame.
            if (
                layout_generation != int(getattr(self, "_layout_generation", 0))
                or self._active_view != role
                or getattr(self, "_screensaver_active", False)
            ):
                return
            if error is not None:
                self._show_camera_preview_error(role, "SNAPSHOT REQUEST FAILED")
                return
            response = _mapping(response)
            status = int(response.get("http_status") or 0)
            if status != 200:
                self._show_camera_preview_error(role, "SNAPSHOT HTTP %d" % status)
                return
            if self._apply_preview_jpeg(role, response.get("jpeg") or b"") is False:
                self._show_camera_preview_error(role, "INVALID CAMERA FRAME")

        self._submit_general(
            "preview",
            fetch_camera_snapshot(
                self.config["health_url"],
                role,
                self.config["timeout_ms"],
            ),
            apply,
            replace=True,
        )

    def _apply_metrics(self, view):
        values = _metrics_view(view)
        # The reducer deliberately retains legacy metrics for compatibility,
        # while a given screen may render only a selected subset.  Drive the
        # update from the live widget tree so a reducer-only key cannot abort
        # initial rendering (or trigger unsafe native teardown in MicroPython).
        for key, tile in self.metric_tiles.items():
            value, tone = values.get(key, ("UNAVAILABLE", "muted"))
            color = self._tone_color(tone)
            tile["value"].set_text(value)
            tile["value"].set_style_text_color(self.lv.color_hex(color), 0)
            tile["tile"].set_style_border_color(self.lv.color_hex(color), 0)

    def _apply_operations(self, operations):
        operations = _operations_view({"operations": operations})
        self._last_operations_view = operations

        def apply_card(key, status, detail, tone, button_text=None, enabled=False):
            widgets = self.operation_cards[key]
            color = self._tone_color(tone)
            widgets["status"].set_text(_safe_text(status, 34))
            widgets["status"].set_style_text_color(self.lv.color_hex(color), 0)
            widgets["detail"].set_text(_safe_text(detail, 120))
            widgets["card"].set_style_border_color(self.lv.color_hex(color), 0)
            button = widgets.get("button")
            label = widgets.get("button_label")
            if button is None or label is None:
                return
            label.set_text(_safe_text(button_text or "NICHT VERFUEGBAR", 28))
            if enabled and not self._operations_request_pending:
                button.remove_state(self.lv.STATE.DISABLED)
                self._set_panel_color(
                    button,
                    (
                        self.DANGER
                        if tone == "danger"
                        else self.WARN if tone == "warn" else self.OK
                    ),
                )
            else:
                button.add_state(self.lv.STATE.DISABLED)
                self._set_panel_color(button, self.DIM)

        petri = operations["petri"]
        petri_error = (
            " | ERR %s" % petri["error_code"] if petri.get("error_code") else ""
        )
        apply_card(
            "petri",
            petri["state"].upper(),
            "%s | %s%s\n%s"
            % (petri["steps"], petri["eta"], petri_error, petri["message"]),
            petri["tone"],
            petri["button"],
            petri.get("action_allowed") is True or petri.get("stop_allowed") is True,
        )
        registration = operations["registration"]
        apply_card(
            "registration",
            registration["status"],
            "Authenticated readiness check\nNo credentials enter LVGL",
            registration["tone"],
            "ERNEUT PRUEFEN" if registration["ready"] else "REGISTRIERUNG PRUEFEN",
            registration.get("action_allowed") is True,
        )
        datahub = operations["datahub"]
        apply_card(
            "datahub",
            datahub["status"],
            "Pending %d | Dead %d\nDataset binding %s"
            % (
                datahub["pending"],
                datahub["dead"],
                "VERIFIED" if datahub["bound"] else "NOT VERIFIED",
            ),
            datahub["tone"],
        )
        recovery = operations["recovery"]
        recovery_error = (
            " | ERR %s" % recovery["error_code"] if recovery.get("error_code") else ""
        )
        apply_card(
            "recovery",
            recovery["state"].upper(),
            "%s%s\nNur gepruefter Home-Pfad" % (recovery["message"], recovery_error),
            recovery["tone"],
            recovery["button"],
            recovery.get("action_allowed") is True
            or recovery.get("stop_allowed") is True,
        )
        identity = operations["identity"]
        review = operations["review"]
        identity_tone = identity.get("tone", "muted")
        review_state = review.get("state") or "IDLE"
        candidate = _mapping(getattr(self, "_manual_review_candidate", {}))
        candidate_id = _safe_text(candidate.get("observation_id") or "", 18)
        if self._manual_review_challenge and candidate_id:
            review_button = "BILD PRUEFEN"
            review_detail = "Candidate %s\nVisuell pruefen" % candidate_id
        elif review.get("pending", 0) > 0:
            review_button = "NAECHSTE PRUEFEN"
            review_detail = "Pending review %d | %s\nNur Backend-Auswahl"
            review_detail = review_detail % (review["pending"], review_state)
        else:
            review_button = "KEINE OFFENE PRUEFUNG"
            review_detail = "Pending review 0 | %s\nRegistry read-only" % review_state
        apply_card(
            "identity",
            "%s / %d PLATES" % (identity["state"], identity.get("plates", 0)),
            "%s\nReview %s"
            % (
                review_detail,
                "READY" if review["configured"] else "UNAVAILABLE",
            ),
            identity_tone,
            review_button,
            bool(
                review.get("configured") is True
                and review.get("pending", 0) > 0
                and (
                    review.get("action_allowed") is True
                    or bool(self._manual_review_challenge)
                )
            ),
        )
        self._apply_manual_review_page()
        history = operations["history"]
        history_ready = history["configured"] and history.get("valid") is True
        apply_card(
            "history",
            "%d RECORDS" % history["records"],
            "History %s | Recent %d\nLatest %s\nExport %s"
            % (
                (
                    "READY"
                    if history_ready
                    else "CHECK" if history["configured"] else "UNAVAILABLE"
                ),
                history["recent"],
                history.get("latest") or "--",
                "READY" if history["export_available"] else "UNAVAILABLE",
            ),
            history.get("tone") or "muted",
        )

    def _apply_production(self, view, operations=None):
        """Render only the bounded #327 status and fixed local actions."""

        if not hasattr(self, "production_cards"):
            return
        production = _production_view(view, operations)

        def apply_card(key, status, detail, tone, button_text=None, enabled=False):
            widgets = self.production_cards[key]
            color = self._tone_color(tone)
            widgets["status"].set_text(_safe_text(status, 36))
            widgets["status"].set_style_text_color(self.lv.color_hex(color), 0)
            widgets["detail"].set_text(_safe_text(detail, 144))
            widgets["card"].set_style_border_color(self.lv.color_hex(color), 0)
            button = widgets.get("button")
            label = widgets.get("button_label")
            if button is None or label is None:
                return
            label.set_text(_safe_text(button_text or "GESPERRT", 28))
            if enabled and not self._operations_request_pending:
                button.remove_state(self.lv.STATE.DISABLED)
                self._set_panel_color(
                    button,
                    (
                        self.DANGER
                        if tone == "danger"
                        else self.WARN if tone == "warn" else self.OK
                    ),
                )
            else:
                button.add_state(self.lv.STATE.DISABLED)
                self._set_panel_color(button, self.DIM)

        apply_card(
            "readiness",
            "READY" if production["ready"] else "MOTION LOCKED",
            "%s\n%s" % (production["blockers_text"], production["recipe"]),
            "ok" if production["ready"] else "danger",
        )
        petri = production["petri"]
        apply_card(
            "workflow",
            "%s / %s" % (petri["state"], petri["process_state"]),
            "PLATE %s | RUN %s\n%s | %s | %d%%\n%s"
            % (
                petri["plate_id"],
                petri["run_id"],
                petri["steps"],
                petri["eta"],
                petri["progress"],
                petri["message"],
            ),
            petri["tone"],
            petri["button"],
            petri["start_allowed"] or petri["stop_required"],
        )
        hardware = production["hardware"]
        apply_card(
            "hardware",
            "READY" if hardware["ready"] else "BLOCKED",
            hardware["detail"],
            hardware["tone"],
        )
        datahub = production["datahub"]
        apply_card(
            "datahub",
            datahub["status"],
            datahub["detail"],
            datahub["tone"],
        )
        recovery = production["recovery"]
        apply_card(
            "recovery",
            recovery["state"],
            "%s\nBackend approval required" % recovery["detail"],
            recovery["tone"],
            recovery["button"],
            recovery["action_allowed"] or recovery["stop_required"],
        )
        ota = production["ota"]
        apply_card(
            "ota",
            ota["status"],
            ota["detail"],
            ota["tone"],
            "UPDATE DETAILS",
            True,
        )
        self.production_stop_button.remove_state(self.lv.STATE.DISABLED)
        self._set_panel_color(self.production_stop_button, self.DANGER)
        self.production_stop_label.set_text("SOFTWARE STOP")

    def _apply_camera(self, widgets, camera):
        color = self._tone_color(camera["tone"])
        self._set_panel_color(widgets["rail"], color)
        self._set_panel_color(widgets["badge"], color)
        widgets["headline"].set_text(camera["headline"])
        widgets["detail"].set_text(camera["detail"])
        # Camera workers continuously refresh an in-memory MJPEG preview so
        # readiness can be monitored.  Never present that volatile counter as
        # a dataset capture: durable images are counted only on the CAPTURE
        # page after the operator presses its start button twice.
        widgets["frames"].set_text("NOT SAVED TO DATASET")
        widgets["reconnects"].set_text(
            "Reconnects  %s    Errors  %s" % (camera["reconnects"], camera["errors"])
        )
        widgets["badge_label"].set_text(
            "LIVE + FRESH" if camera["healthy"] else "CHECK CAMERA"
        )

    def _apply_ota(self, ota):
        color = self._tone_color(ota["tone"])
        self._set_panel_color(self.update_rail, color)
        self.update_headline.set_text(ota["headline"])
        self.update_headline.set_style_text_color(self.lv.color_hex(color), 0)
        self.update_detail.set_text(ota["detail"])
        self.update_current_version.set_text(ota["current_version"])
        self.update_available_version.set_text(ota["available_version"])
        badge_color = self._tone_color(ota.get("verification_tone", "muted"))
        self._set_panel_color(self.update_verification_badge, badge_color)
        self.update_verification_label.set_text(
            _safe_text(ota.get("verification_badge") or "STATUS UNKNOWN", 36)
        )
        enabled = ota.get("action_allowed") is True and not self._update_request_pending
        if enabled:
            self.update_button.remove_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.update_button, self.OK)
            self.update_button_label.set_text("JETZT UPDATEN")
        else:
            self.update_button.add_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.update_button, self.DIM)
            self.update_button_label.set_text(ota["button"])

    def _apply_capture(self, capture):
        color = self._tone_color(capture["tone"])
        self._set_panel_color(self.capture_rail, color)
        self.capture_headline.set_text(capture["headline"])
        self.capture_headline.set_style_text_color(self.lv.color_hex(color), 0)
        self.capture_detail.set_text(capture["detail"])
        progress = int(capture.get("progress") or 0)
        progress = min(max(progress, 0), 100)
        fill_width = max(1, int(self.capture_progress_width * progress / 100))
        self.capture_progress_fill.set_size(fill_width, 14)
        self._set_panel_color(self.capture_progress_fill, color)
        self.capture_progress_text.set_text(
            "%d / %d ZEITPUNKTE"
            % (
                capture["completed_timepoints"],
                capture["planned_timepoints"],
            )
        )
        self.capture_run_id.set_text("RUN %s" % capture["run_id"])
        self.capture_tool_saved.set_text("%d / 15 GESPEICHERT" % capture["tool_saved"])
        self.capture_workspace_saved.set_text(
            "%d / 15 GESPEICHERT" % capture["workspace_saved"]
        )
        dataset_color = self._tone_color(capture.get("dataset_tone", "warn"))
        self.capture_dataset_sync.set_text(capture["dataset_text"])
        self.capture_dataset_sync.set_style_text_color(
            self.lv.color_hex(dataset_color),
            0,
        )
        evidence_color = self._tone_color(capture.get("evidence_tone", "muted"))
        self.capture_evidence.set_text(
            _safe_text(
                capture.get("evidence_text") or "LOCAL MANIFEST UNAVAILABLE | ERR --",
                96,
            )
        )
        self.capture_evidence.set_style_text_color(
            self.lv.color_hex(evidence_color),
            0,
        )
        enabled = (
            capture.get("action_allowed") is True or capture.get("stop_allowed") is True
        ) and not self._capture_request_pending
        if enabled:
            self.capture_button.remove_state(self.lv.STATE.DISABLED)
            button_color = (
                self.DANGER
                if capture.get("stop_allowed") is True
                else self.WARN if capture.get("state") == "confirming" else self.OK
            )
            self._set_panel_color(self.capture_button, button_color)
        else:
            self.capture_button.add_state(self.lv.STATE.DISABLED)
            self._set_panel_color(self.capture_button, self.DIM)
        self.capture_button_label.set_text(capture["button"])

    def _apply(self, view):
        # Recover universal STOP after a frontend restart during an
        # authoritative active search.  Admission may have happened in the
        # previous UI process, so local click history is not required safety
        # evidence.
        if _search_requires_visible_stop(view):
            self._motion_stop_latched = True
            self._motion_stop_origin = "search"
        if _operations_require_visible_stop(view):
            self._motion_stop_latched = True
            self._motion_stop_origin = (
                "production"
                if getattr(self, "_active_view", "") == "production"
                else "operations"
            )
        view, self._motion_stop_latched = _reconcile_motion_stop_latch(
            view,
            getattr(self, "_last_capture_view", {}),
            getattr(self, "_motion_stop_latched", False),
            origin=getattr(self, "_motion_stop_origin", ""),
        )
        if not self._motion_stop_latched:
            self._motion_stop_origin = ""
        self._last_view = view
        self._screensaver_metrics_alarm = _metrics_require_visible_alarm(view)
        runtime_role = _runtime_role_view(view)
        color = self._tone_color(view["tone"])
        self.subtitle.set_text(runtime_role["subtitle"])
        self._set_panel_color(self.header_badge, color)
        self.header_badge_label.set_text(
            runtime_role["online"] if view["ready"] else runtime_role["check"]
        )
        self._set_panel_color(self.hero_rail, color)
        self.hero_state.set_text(view["state"])
        self.hero_state.set_style_text_color(self.lv.color_hex(color), 0)
        self.hero_detail.set_text(view["detail"])
        self.camera_metric["value"].set_text("%d / 2 LIVE" % view["camera_count"])
        motion = view["motion"]
        xarm = view["xarm"]
        self.safety_metric["value"].set_text(
            "XARM + LOCKED"
            if motion["verified_locked"] and xarm["connected"]
            else "VERIFY"
        )
        self._apply_camera(self.camera_cards["tool"], view["cameras"]["tool"])
        self._apply_camera(self.camera_cards["workspace"], view["cameras"]["workspace"])
        self._apply_camera_page("tool", view["cameras"]["tool"])
        self._apply_camera_page("workspace", view["cameras"]["workspace"])
        motion_color = self._tone_color(motion["tone"])
        self._set_panel_color(self.motion_card["rail"], motion_color)
        self._set_panel_color(self.motion_card["badge"], motion_color)
        self.motion_card["headline"].set_text(
            "%s / %s" % (xarm["summary"], motion["headline"])
        )
        self.motion_card["detail"].set_text(xarm["detail"])
        self.motion_card["policy"].set_text(motion["policy"])
        self.motion_card["badge_label"].set_text(motion["badge"])
        ota = view["ota"]
        self._last_ota_view = ota
        if ota["status"] not in ("checking", "busy", "pending_restart"):
            self._update_request_pending = False
        self._apply_ota(ota)
        capture = view["capture"]
        self._last_capture_view = capture
        if capture["state"] not in ("starting", "stopping"):
            self._capture_request_pending = False
        if capture["state"] != "confirming" and not self._capture_request_pending:
            self._capture_start_challenge = ""
        self._apply_capture(capture)
        search = _motion_search_view(view)
        if self._motion_search_challenge:
            search = dict(search)
            search.update(
                {
                    "configured": True,
                    "action_allowed": True,
                    "request_allowed": True,
                    "request_result": "confirm",
                    "state": "ready",
                    "tone": "warn",
                    "headline": "WERKZEUGSUCHE ERNEUT BESTAETIGEN",
                    "detail": "Arbeitsraum frei und physischer Not-Aus erreichbar?",
                    "button": "NOCHMAL BESTAETIGEN",
                    "workflow_progress": 50,
                    "workflow_stage": "2 / 4  ZWEITE BESTAETIGUNG",
                    "stop_allowed": False,
                }
            )
        self._last_motion_search_view = search
        self._apply_system(view)
        self._apply_digital_twin(view)
        displayed_workspace_teach = self._apply_workspace_teach(view)
        if isinstance(displayed_workspace_teach, dict):
            view = dict(view)
            view["workspace_teach"] = displayed_workspace_teach
            self._last_view = view
        self._apply_tenant_auth(view)
        self._apply_hand_training(view)
        self._apply_robot_metrics(view)
        if (
            getattr(self, "_safety_configuration_local_pending", False)
            and not getattr(self, "_safety_configuration_challenge", "")
            and not getattr(self, "_safety_configuration_request_pending", False)
        ):
            self._safety_configuration_local_pending = False
        self._apply_safety_configuration(view)
        operations = _operations_view(view)
        self._last_operations_view = operations
        if self._petri_start_challenge:
            token, _record = self._challenge_for_rebuild(
                "_petri_start_challenge", _monotonic_ms()
            )
            if not token:
                self._petri_start_challenge = ""
            else:
                operations = dict(operations)
                petri = dict(operations["petri"])
                petri.update(
                    {
                        "state": "confirming",
                        "tone": "warn",
                        "action_allowed": True,
                        "stop_allowed": False,
                        "button": "NOCHMAL BESTAETIGEN",
                        "message": (
                            "Arbeitsraum frei und physischer Not-Aus erreichbar?"
                        ),
                    }
                )
                operations["petri"] = petri
                self._last_operations_view = operations
        if self._recovery_start_challenge:
            token, _record = self._challenge_for_rebuild(
                "_recovery_start_challenge", _monotonic_ms()
            )
            if not token:
                self._recovery_start_challenge = ""
            else:
                operations = dict(operations)
                recovery = dict(operations["recovery"])
                recovery.update(
                    {
                        "state": "confirming",
                        "tone": "warn",
                        "action_allowed": True,
                        "stop_allowed": False,
                        "button": "NOCHMAL BESTAETIGEN",
                        "message": "Recovery-Bereich frei und Not-Aus erreichbar?",
                    }
                )
                operations["recovery"] = recovery
                self._last_operations_view = operations
        if self._manual_review_challenge:
            operations = dict(operations)
            review = dict(operations["review"])
            review.update({"state": "CONFIRMING", "action_allowed": True})
            operations["review"] = review
        self._apply_operations(operations)
        self._apply_production(view, operations)
        self._apply_manual_review_page()
        self._apply_software_stop_nav(capture)
        if getattr(
            self, "_motion_stop_latched", False
        ) or _capture_requires_visible_stop(view):
            origin = getattr(self, "_motion_stop_origin", "")
            required_view = (
                (
                    "digital_twin"
                    if getattr(self, "_active_view", "") == "digital_twin"
                    else "system"
                )
                if origin == "search"
                else origin if origin in ("operations", "production") else "capture"
            )
            if self._active_view != required_view:
                self._activate_view(required_view, invalidate=False)
        self._apply_launcher(view)
        self._apply_metrics(view)
        self._set_panel_color(self.footer_dot, color)
        self.footer_status.set_text(self._footer_input_status(view["footer"]))
        now = _clock_text()
        self.updated_label.set_text("UPDATED %s" % now[11:])
        # A fresh safety/alarm/active-operation snapshot immediately uncovers
        # the UI and grants a full idle interval after it clears.
        self._enforce_screensaver_visibility()
        # Labwc applies fullscreen just after SDL maps the Xwayland window.
        # Force a complete repaint so the resize cannot leave static labels
        # outside the compositor's initial damage region.
        self.screen.invalidate()

    def refresh(self, _timer=None):
        action_epoch = int(getattr(self, "_action_epoch", 0))
        health_epoch = int(getattr(self, "_health_poll_epoch", 0)) + 1
        self._health_poll_epoch = health_epoch
        poll_started_ms = _monotonic_ms()

        def apply(response, error):
            # A snapshot begun before a physical action is stale even if it
            # completes afterward.  Wait for the next poll rather than
            # clearing an optimistic STOP/challenge state with old data.
            if action_epoch != int(getattr(self, "_action_epoch", 0)) or (
                health_epoch != int(getattr(self, "_health_poll_epoch", 0))
            ):
                return
            if error is not None:
                view = self._offline_view()
            else:
                try:
                    response = _mapping(response)
                    if response.get("transport_error"):
                        view = self._offline_view()
                    else:
                        view = present_health(response)
                except Exception:
                    view = self._offline_view()
            self._pending_health_poll_started_ms = poll_started_ms
            try:
                self._apply(view)
            finally:
                self._pending_health_poll_started_ms = None

        submitted = self._submit_general(
            "health",
            fetch_health(self.config["health_url"], self.config["timeout_ms"]),
            apply,
            replace=True,
        )
        if not submitted:
            # Submission failure is itself authoritative local transport
            # evidence. Reveal diagnostics now; do not leave an old black or
            # optimistic view visible until the broker happens to recover.
            apply(None, RuntimeError("health request was not accepted"))
            return False
        return True

    def _offline_view(self):
        runtime_role = _runtime_role_view("")
        return {
            "health_authoritative": False,
            "deployment_mode": runtime_role["mode"],
            "runtime_role": runtime_role,
            "ready": False,
            "tone": "danger",
            "state": "RUNTIME OFFLINE",
            "detail": "Waiting for the local runtime",
            "tool": "Tool: unavailable",
            "workspace": "Workspace: unavailable",
            "camera_count": 0,
            "cameras": {
                "tool": _camera_view({}, "tool"),
                "workspace": _camera_view({}, "workspace"),
            },
            "motion": _motion_view({}),
            "ota": _ota_view({}),
            "capture": _capture_view({}),
            "xarm": _xarm_view({}),
            "digital_twin": _digital_twin_view({}),
            "workspace_teach": _workspace_teach_view({}),
            "workspace_boundary": _workspace_boundary_view({}),
            "tenant_auth": _tenant_auth_view({}),
            "hand_training": _hand_training_view({}),
            "motion_search": _motion_search_view({}),
            "operations": _operations_view({}),
            "diagnostics": {"schema_version": 1},
            "footer": "LOCAL HEALTH REQUEST FAILED",
            "problems": "Checks: local health unavailable",
        }

    def run(self):
        while True:
            self.lv.timer_handler()
            if hasattr(time, "sleep_ms"):
                time.sleep_ms(5)
            else:  # CPython-only convenience for local smoke tests.
                time.sleep(0.005)


def main():
    import lvgl as lv

    config = load_config()
    lv.init()
    frontend = GatewayStatusFrontend(lv, config)
    frontend.run()


if __name__ == "__main__":
    main()
