{
    let (connection_panel, connection_body) = build_panel("Relay");
    let server_entry = gtk::Entry::new();
    server_entry.add_css_class("server-entry");
    server_entry.set_hexpand(true);
    server_entry.set_width_chars(11);
    server_entry.set_text(server_addr);
    server_entry.set_tooltip_text(Some(
        "Relay host address. If no scheme is provided, Lesavka uses https://.",
    ));
    let relay_grid = gtk::Grid::new();
    relay_grid.set_column_homogeneous(false);
    relay_grid.set_column_spacing(8);
    relay_grid.set_hexpand(true);
    relay_grid.set_row_spacing(8);
    relay_grid.attach(&server_entry, 0, 0, 1, 1);
    let certs_button = rail_button("Certs", "Install or replace the client TLS enrollment bundle.");
    certs_button.set_hexpand(false);
    stabilize_button(&certs_button, 66);
    relay_grid.attach(&certs_button, 1, 0, 1, 1);
    let start_button = rail_button("Connect", "Start or stop relay.");
    start_button.add_css_class("suggested-action");
    start_button.set_hexpand(false);
    relay_grid.attach(&start_button, 2, 0, 1, 1);
    connection_body.append(&relay_grid);
    let recovery_heading = gtk::Label::new(Some("Recover\nUpstream"));
    recovery_heading.add_css_class("subgroup-title");
    recovery_heading.set_halign(gtk::Align::Start);
    recovery_heading.set_justify(gtk::Justification::Center);
    let recovery_row = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    recovery_row.set_hexpand(true);
    recovery_heading.set_width_chars(RELAY_SUBGROUP_LABEL_WIDTH);
    recovery_row.append(&recovery_heading);
    let recovery_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    recovery_buttons.set_hexpand(true);
    recovery_buttons.set_halign(gtk::Align::End);
    recovery_buttons.set_homogeneous(false);
    let usb_recover_button = rail_button(
        "HID",
        "Soft recovery: reopen keyboard/mouse HID handles and verify enumeration without detaching the USB gadget.",
    );
    let uac_recover_button = rail_button(
        "Audio",
        "Soft recovery: retire the stale upstream audio epoch so bundled mic+camera reconnect without resetting USB or changing calibration.",
    );
    let uvc_recover_button = rail_button(
        "Video",
        "Soft recovery: retire the virtual webcam spool pipeline so video reconnects without restarting the gadget.",
    );
    usb_recover_button.set_hexpand(false);
    uac_recover_button.set_hexpand(false);
    uvc_recover_button.set_hexpand(false);
    recovery_buttons.append(&usb_recover_button);
    recovery_buttons.append(&uac_recover_button);
    recovery_buttons.append(&uvc_recover_button);
    recovery_row.append(&recovery_buttons);
    connection_body.append(&recovery_row);
    connection_body.append(&gtk::Separator::new(gtk::Orientation::Horizontal));
    let calibration_heading = gtk::Label::new(Some("Audio/Video\nUpstream\nCalibration"));
    calibration_heading.add_css_class("subgroup-title");
    calibration_heading.set_halign(gtk::Align::Start);
    calibration_heading.set_justify(gtk::Justification::Center);
    calibration_heading.set_width_chars(RELAY_SUBGROUP_LABEL_WIDTH);
    let calibration_row = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    calibration_row.set_hexpand(true);
    calibration_row.append(&calibration_heading);
    let calibration_buttons = gtk::Grid::new();
    calibration_buttons.set_column_homogeneous(true);
    calibration_buttons.set_column_spacing(8);
    calibration_buttons.set_row_spacing(6);
    calibration_buttons.set_hexpand(true);
    let calibration_default_button = rail_button(
        "Default",
        "Restore the saved upstream A/V calibration profile for this relay.",
    );
    let calibration_factory_button = rail_button(
        "Factory",
        "Restore the release-shipped MJPEG upstream A/V calibration.",
    );
    let calibration_blind_button = rail_button(
        "Blind",
        "Estimate upstream A/V calibration from live queue and timestamp telemetry; use only when no test rig is attached.",
    );
    let calibration_minus_button = rail_button(
        "-5 ms",
        "Move upstream audio 5 ms earlier relative to video for the active session.",
    );
    let calibration_plus_button = rail_button(
        "+5 ms",
        "Move upstream audio 5 ms later relative to video for the active session.",
    );
    let calibration_rig_button = rail_button(
        "Rig...",
        "Open the test-equipment calibration path for measuring a new saved default.",
    );
    calibration_buttons.attach(&calibration_default_button, 0, 0, 1, 1);
    calibration_buttons.attach(&calibration_factory_button, 1, 0, 1, 1);
    calibration_buttons.attach(&calibration_blind_button, 2, 0, 1, 1);
    calibration_buttons.attach(&calibration_minus_button, 0, 1, 1, 1);
    calibration_buttons.attach(&calibration_plus_button, 1, 1, 1, 1);
    calibration_buttons.attach(&calibration_rig_button, 2, 1, 1, 1);
    calibration_row.append(&calibration_buttons);
    connection_body.append(&calibration_row);

    connection_body.append(&gtk::Separator::new(gtk::Orientation::Horizontal));
    let power_heading = gtk::Label::new(Some("GPIO Power"));
    power_heading.add_css_class("subgroup-title");
    power_heading.set_halign(gtk::Align::Start);

    let power_shell = gtk::Box::new(gtk::Orientation::Vertical, 6);
    power_shell.set_halign(gtk::Align::Fill);
    let power_row = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    power_row.set_hexpand(true);
    power_heading.set_width_chars(RELAY_SUBGROUP_LABEL_WIDTH);
    power_row.append(&power_heading);
    let power_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    power_buttons.set_hexpand(true);
    power_buttons.set_homogeneous(true);
    let power_on_button = gtk::Button::with_label("On");
    power_on_button.set_hexpand(true);
    stabilize_button(&power_on_button, 52);
    power_on_button.add_css_class("pill-toggle");
    let power_auto_button = gtk::Button::with_label("Auto");
    power_auto_button.set_hexpand(true);
    stabilize_button(&power_auto_button, 52);
    power_auto_button.add_css_class("pill-toggle");
    let power_off_button = gtk::Button::with_label("Off");
    power_off_button.set_hexpand(true);
    stabilize_button(&power_off_button, 52);
    power_off_button.add_css_class("pill-toggle");
    let power_detail = gtk::Label::new(Some("Capture power status is loading..."));
    power_detail.add_css_class("dim-label");
    power_detail.set_wrap(true);
    power_detail.set_xalign(0.0);
    power_buttons.append(&power_on_button);
    power_buttons.append(&power_auto_button);
    power_buttons.append(&power_off_button);
    power_row.append(&power_buttons);
    power_shell.append(&power_row);
    connection_body.append(&power_shell);
    let routing_heading = gtk::Label::new(Some("Inputs"));
    routing_heading.add_css_class("subgroup-title");
    routing_heading.set_halign(gtk::Align::Start);
    connection_body.append(&gtk::Separator::new(gtk::Orientation::Horizontal));

    let routing_row = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    routing_row.set_hexpand(true);
    routing_heading.set_width_chars(RELAY_SUBGROUP_LABEL_WIDTH);
    routing_row.append(&routing_heading);
    let routing_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    routing_buttons.set_hexpand(true);
    routing_buttons.set_homogeneous(true);
    let input_toggle_button = gtk::Button::with_label("Route");
    input_toggle_button.set_hexpand(true);
    stabilize_button(&input_toggle_button, 106);
    input_toggle_button.set_tooltip_text(Some("Swap input ownership."));
    let swap_key_button = gtk::Button::with_label("Set Swap Key");
    swap_key_button.set_hexpand(true);
    stabilize_button(&swap_key_button, 106);
    routing_buttons.append(&input_toggle_button);
    routing_buttons.append(&swap_key_button);
    routing_row.append(&routing_buttons);
    connection_body.append(&routing_row);

    connection_body.append(&gtk::Separator::new(gtk::Orientation::Horizontal));
    let tools_heading = gtk::Label::new(Some("Tools"));
    tools_heading.add_css_class("subgroup-title");
    tools_heading.set_halign(gtk::Align::Start);
    let tools_row = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    tools_row.set_hexpand(true);
    tools_heading.set_width_chars(RELAY_SUBGROUP_LABEL_WIDTH);
    tools_row.append(&tools_heading);
    let tools_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    tools_buttons.set_hexpand(true);
    tools_buttons.set_homogeneous(false);
    let clipboard_button = rail_button("Clipboard", "Type clipboard remotely.");
    clipboard_button.set_hexpand(true);
    let wake_combo = gtk::ComboBoxText::new();
    wake_combo.add_css_class("compact-combo");
    for (id, label) in [
        ("off", "Wake: off"),
        ("5", "Wake: 5m"),
        ("10", "Wake: 10m"),
        ("20", "Wake: 20m"),
        ("30", "Wake: 30m"),
        ("60", "Wake: 60m"),
    ] {
        wake_combo.append(Some(id), label);
    }
    wake_combo.set_active_id(Some("off"));
    wake_combo.set_hexpand(false);
    wake_combo.set_size_request(92, 36);
    wake_combo.set_tooltip_text(Some(
        "When remote input is routed and no HID input has been relayed for the selected time, send a tiny random mouse nudge to keep the RCT awake.",
    ));
    tools_buttons.append(&clipboard_button);
    tools_buttons.append(&wake_combo);
    tools_row.append(&tools_buttons);
    connection_body.append(&tools_row);
    operations.append(&connection_panel);

    let (diagnostics_panel, diagnostics_body) = build_panel("Diagnostics");
    diagnostics_panel.set_vexpand(true);
    diagnostics_panel.set_valign(gtk::Align::Fill);
    diagnostics_body.set_vexpand(true);
    let diagnostics_toolbar = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    diagnostics_toolbar.set_homogeneous(true);
    let diagnostics_copy_button = gtk::Button::with_label("Copy Report");
    stabilize_button(&diagnostics_copy_button, 112);
    let diagnostics_popout_button = gtk::Button::with_label("Break Out");
    stabilize_button(&diagnostics_popout_button, 112);
    diagnostics_toolbar.append(&diagnostics_copy_button);
    diagnostics_toolbar.append(&diagnostics_popout_button);
    let diagnostics_log = Rc::new(RefCell::new(DiagnosticsLog::new(16)));
    let diagnostics_label = gtk::Label::new(None);
    diagnostics_label.add_css_class("status-log");
    diagnostics_label.set_selectable(true);
    diagnostics_label.set_xalign(0.0);
    diagnostics_label.set_yalign(0.0);
    diagnostics_label.set_wrap(true);
    diagnostics_label.set_wrap_mode(pango::WrapMode::WordChar);
    diagnostics_label.set_halign(gtk::Align::Start);
    diagnostics_label.set_valign(gtk::Align::Start);
    diagnostics_label.set_hexpand(true);
    diagnostics_label.set_width_chars(1);
    let diagnostics_shell = gtk::Box::new(gtk::Orientation::Vertical, 0);
    diagnostics_shell.set_hexpand(true);
    diagnostics_shell.set_vexpand(false);
    diagnostics_shell.append(&diagnostics_label);
    let diagnostics_scroll = gtk::ScrolledWindow::builder()
        .hexpand(true)
        .vexpand(true)
        .min_content_height(SIDE_LOG_RECOVERY_MIN_HEIGHT)
        .child(&diagnostics_shell)
        .build();
    diagnostics_scroll.set_propagate_natural_width(false);
    diagnostics_scroll.set_propagate_natural_height(false);
    diagnostics_body.append(&diagnostics_toolbar);
    diagnostics_body.append(&diagnostics_scroll);
    operations.append(&diagnostics_panel);

    let (console_panel, console_body) = build_panel("Log");
    console_panel.set_vexpand(true);
    console_panel.set_valign(gtk::Align::Fill);
    console_body.set_vexpand(true);
    let console_toolbar = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    let session_log_level = Rc::new(RefCell::new(ConsoleLogLevel::default()));
    let console_level_combo = gtk::ComboBoxText::new();
    for level in ConsoleLogLevel::ALL {
        console_level_combo.append(Some(level.id()), level.label());
    }
    console_level_combo.set_active_id(Some(ConsoleLogLevel::default().id()));
    console_level_combo.set_size_request(78, 36);
    console_level_combo.set_tooltip_text(Some("Show relay logs at this level or higher."));
    let console_copy_button = gtk::Button::with_label("Copy");
    console_copy_button.set_tooltip_text(Some("Copy visible log."));
    let console_popout_button = gtk::Button::with_label("Break Out");
    console_popout_button.set_tooltip_text(Some("Break out the log window."));
    let console_buttons = gtk::Box::new(gtk::Orientation::Horizontal, 8);
    console_buttons.set_hexpand(true);
    console_buttons.set_homogeneous(true);
    console_copy_button.set_hexpand(true);
    console_popout_button.set_hexpand(true);
    console_buttons.append(&console_copy_button);
    console_buttons.append(&console_popout_button);
    console_toolbar.append(&console_level_combo);
    console_toolbar.append(&console_buttons);
    let status_label = gtk::Label::new(Some("Session log ready."));
    status_label.add_css_class("status-line");
    status_label.set_halign(gtk::Align::Start);
    status_label.set_wrap(true);
    status_label.set_xalign(0.0);
    let session_log_buffer = gtk::TextBuffer::new(None);
    session_log_buffer.create_tag(Some("log-launcher"), &[("foreground", &"#8bd5ca")]);
    session_log_buffer.create_tag(Some("log-relay"), &[("foreground", &"#89b4fa")]);
    session_log_buffer.create_tag(Some("log-preview"), &[("foreground", &"#cba6f7")]);
    session_log_buffer.create_tag(Some("log-stderr"), &[("foreground", &"#f9e2af")]);
    session_log_buffer.create_tag(Some("log-warn"), &[("foreground", &"#fab387")]);
    session_log_buffer.create_tag(Some("log-error"), &[("foreground", &"#f38ba8")]);
    super::ui_runtime::append_session_log(&session_log_buffer, "[launcher] Session log ready.");
    let session_log_view = gtk::TextView::with_buffer(&session_log_buffer);
    session_log_view.add_css_class("status-log");
    session_log_view.set_editable(false);
    session_log_view.set_cursor_visible(false);
    session_log_view.set_monospace(true);
    session_log_view.set_wrap_mode(gtk::WrapMode::WordChar);
    let log_scroll = gtk::ScrolledWindow::builder()
        .hexpand(true)
        .vexpand(true)
        .min_content_height(SIDE_LOG_RECOVERY_MIN_HEIGHT)
        .child(&session_log_view)
        .build();
    log_scroll.set_propagate_natural_width(false);
    log_scroll.set_propagate_natural_height(false);
    console_body.append(&console_toolbar);
    console_body.append(&log_scroll);
    operations.append(&console_panel);

    {
        let buffer = session_log_buffer.clone();
        let view = session_log_view.clone();
        status_label.connect_notify_local(Some("label"), move |label, _| {
            super::ui_runtime::append_session_log(&buffer, &format!("[launcher] {}", label.text()));
            let mut end = buffer.end_iter();
            view.scroll_to_iter(&mut end, 0.0, false, 0.0, 1.0);
        });
    }

    let preview = match LauncherPreview::new(server_addr.to_string()) {
        Ok(preview) => Some(Rc::new(preview)),
        Err(err) => {
            status_label.set_text(&format!("Preview unavailable: {err}"));
            None
        }
    };

    OperationsRailContext {
        server_entry,
        start_button,
        certs_button,
        clipboard_button,
        wake_combo,
        usb_recover_button,
        uac_recover_button,
        uvc_recover_button,
        calibration_default_button,
        calibration_factory_button,
        calibration_blind_button,
        calibration_minus_button,
        calibration_plus_button,
        calibration_rig_button,
        power_auto_button,
        power_on_button,
        power_off_button,
        power_detail,
        input_toggle_button,
        swap_key_button,
        diagnostics_copy_button,
        diagnostics_popout_button,
        diagnostics_log,
        diagnostics_label,
        diagnostics_scroll,
        console_copy_button,
        console_popout_button,
        console_level_combo,
        session_log_level,
        status_label,
        session_log_buffer,
        session_log_view,
        preview,
    }
}
