${['models.speech', 'models.clean', 'models.translate'].map((key) => html`${LL.t(key)}`)}
<${Row} id="tier" title=${LL.t('model')} desc=${LL.t('model.desc')}>
@@ -232,6 +244,7 @@
<${Row} id="version" title=${LL.t('version')} desc=${LL.t('version.desc')}>
${m.version}
/>
+ <${Update} u=${m.update}/>
`;
// Turning a cloud step on needs the user's consent every time. C# says when to ask; the safe answer is the first button.
diff --git a/src/LiveLingo.Desktop/Web/Assets/styles/settings.css b/src/LiveLingo.Desktop/Web/Assets/styles/settings.css
index c028da4..494c0b8 100644
--- a/src/LiveLingo.Desktop/Web/Assets/styles/settings.css
+++ b/src/LiveLingo.Desktop/Web/Assets/styles/settings.css
@@ -25,6 +25,11 @@ button.danger:hover { background: var(--hover); }
.chips { display: flex; flex-wrap: wrap; gap: 8px; padding: 16px 0; }
+.progress { position: relative; height: 6px; margin-top: 8px; overflow: hidden; border-radius: 999px; background: var(--line-strong); }
+.progress span { display: block; height: 100%; border-radius: inherit; background: var(--accent); transition: width .2s; }
+.progress.indeterminate span { width: 35%; animation: slide 1.1s ease-in-out infinite; }
+@keyframes slide { from { transform: translateX(-100%); } to { transform: translateX(300%); } }
+
.polish { padding-top: 12px; border-top: 1px solid var(--line); }
.polish-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.polish-head h2 { display: flex; align-items: center; gap: 8px; }
diff --git a/src/LiveLingo.Desktop/Web/SettingsIntents.cs b/src/LiveLingo.Desktop/Web/SettingsIntents.cs
index f933cdf..26cfd8f 100644
--- a/src/LiveLingo.Desktop/Web/SettingsIntents.cs
+++ b/src/LiveLingo.Desktop/Web/SettingsIntents.cs
@@ -1,3 +1,4 @@
+using LiveLingo.Desktop.Services.Update;
using LiveLingo.Desktop.Settings;
using Microsoft.Extensions.Logging;
@@ -10,12 +11,16 @@ namespace LiveLingo.Desktop.Web;
internal sealed class SettingsIntents : IIntentHandler
{
private readonly SettingsViewModel _vm;
+ private readonly UpdateChecks? _updates;
+ private readonly Action