+
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/frontend/src/ui-core.ts b/src/trx-client/trx-frontend/trx-frontend-http/frontend/src/ui-core.ts
index 4bf33772..4e7f0591 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/frontend/src/ui-core.ts
+++ b/src/trx-client/trx-frontend/trx-frontend-http/frontend/src/ui-core.ts
@@ -317,7 +317,10 @@ function elementById(id: string): T {
const element = document.getElementById(id);
if (element) body.appendChild(element);
});
- tray.appendChild(details);
+ // Ahead of the collapsibles the markup ships: the radio's own settings
+ // come before audio and the scheduler, and appending would put the
+ // section built here last whatever the markup says.
+ tray.insertBefore(details, document.getElementById("audio-controls"));
api.applyLayout(savedLayoutName(), { persist: false });
}
}
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/frontend/tests/browser-smoke.mjs b/src/trx-client/trx-frontend/trx-frontend-http/frontend/tests/browser-smoke.mjs
index a00b9b8b..e90c2989 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/frontend/tests/browser-smoke.mjs
+++ b/src/trx-client/trx-frontend/trx-frontend-http/frontend/tests/browser-smoke.mjs
@@ -23,6 +23,15 @@ try {
await page.locator("summary", { hasText: "Audio controls" }).click();
assert.equal(await page.locator("#rx-audio-btn").count(), 1);
+ // Section order in the tray. "Advanced radio controls" is built at runtime,
+ // so it lands wherever ui-core puts it rather than where the markup says —
+ // appending, as it once did, always left it last.
+ const sections = await page.evaluate(() =>
+ [...document.querySelectorAll(".controls-tray > details")].map((section) =>
+ section.querySelector("summary").textContent.trim()));
+ assert.deepEqual(sections, ["Advanced radio controls", "Audio controls", "Scheduler controls"],
+ `tray sections are ${JSON.stringify(sections)}`);
+
// Mode is a button group over a hidden