diff --git a/README.md b/README.md
index 9502867..85123cb 100644
--- a/README.md
+++ b/README.md
@@ -303,13 +303,13 @@ A tool that answers everything is easy to build. This is the other kind.
### Installing it
-**Word on the web** — Home → Add-ins → More Add-ins → My Add-ins → **Upload My Add-in**, and choose
-[`src/SignsOfAI.Word/manifest.xml`](src/SignsOfAI.Word/manifest.xml).
+**[The add-in's page →](https://peopleworks.github.io/SignsofAI/word)** — what it does, both
+install routes, and what it refuses to do, in English and Spanish.
-**Word for Windows** has no upload button and reads a shared-folder catalogue instead; the steps are
-in [`src/SignsOfAI.Word/README.md`](src/SignsOfAI.Word/README.md).
-
-First load is about 3.4 MB — the .NET runtime, cached afterwards. It is not in the Office Store yet.
+The short version: on the web it is Home → Add-ins → More Add-ins → My Add-ins → **Upload My Add-in**
+with [`src/SignsOfAI.Word/manifest.xml`](src/SignsOfAI.Word/manifest.xml). Word for Windows has no
+upload button and reads a shared-folder catalogue instead, which
+[`src/SignsOfAI.Word/README.md`](src/SignsOfAI.Word/README.md) walks through.
### PowerPoint is a different product, on purpose
diff --git a/src/SignsOfAI.UI/Layout/MainLayout.razor b/src/SignsOfAI.UI/Layout/MainLayout.razor
index b513c24..1a28574 100644
--- a/src/SignsOfAI.UI/Layout/MainLayout.razor
+++ b/src/SignsOfAI.UI/Layout/MainLayout.razor
@@ -22,6 +22,9 @@
@L["nav.baseline"]
@L["nav.originality"]
@L["nav.catalog"]
+ @* No host condition, unlike the two below: somebody using the desktop app writes in
+ Word too, and the add-in is useful to them for the same reasons. *@
+ @L["nav.word"]
@* Only where there is something to gain by downloading it. The same signal as the
folder link above, and for the same reason: this host cannot open a folder, so a
better host exists for this machine and hiding that would be the lowest-common-
diff --git a/src/SignsOfAI.UI/Pages/Download.razor b/src/SignsOfAI.UI/Pages/Download.razor
index 6a24ecd..cffcd10 100644
--- a/src/SignsOfAI.UI/Pages/Download.razor
+++ b/src/SignsOfAI.UI/Pages/Download.razor
@@ -106,28 +106,15 @@ else
@L.M("dl.zip.body")
-@* Not the desktop app, and placed after it rather than beside it: this is the other way to run the
- engine on your own machine, in the application where the document already is. The privacy claim is
- the same one and it is the reason this host is worth having at all, so it is stated rather than
- implied. *@
+@* The Word add-in has its own page. This is a pointer, deliberately short: the argument lived here
+ in full for a few hours and that is two copies of the same paragraphs, which is how one of them
+ ends up saying something the other stopped saying. *@
@L["dl.word.title"]
@L["dl.word.lede"]
- @L.M("dl.word.why")
-
-
- - @L.M("dl.word.install.web")
- - @L.M("dl.word.install.desktop")
-
-
-
- @L["dl.word.manifest"]
- ·
- @L["dl.word.steps"]
-
- @L["dl.word.size"]
+
@code {
diff --git a/src/SignsOfAI.UI/Pages/WordAddin.razor b/src/SignsOfAI.UI/Pages/WordAddin.razor
new file mode 100644
index 0000000..7f45b16
--- /dev/null
+++ b/src/SignsOfAI.UI/Pages/WordAddin.razor
@@ -0,0 +1,108 @@
+@page "/word"
+@using SignsOfAI.Core.Calibration
+@inherits LocalizedComponent
+
+@*
+ The Word add-in's own page, the way the desktop app has one.
+
+ It leads with what the add-in refuses to do, because that is what makes it different from every
+ other add-in in this category — not as modesty, but because a reader deciding whether to let a
+ tool near coursework is deciding about exactly those refusals.
+
+ The floor and the published rate are read from the calibration the build ships rather than typed
+ here. That page went stale for six days in August by being typed; this one cannot.
+*@
+
+@L["wa.pagetitle"]
+
+
+ @L["wa.h1"]
+ @L["wa.tagline"]
+
+
+@* Installing first: somebody who arrived from the README or a video wants the manifest, not an
+ argument they have already been convinced by. *@
+
+ @L["wa.install.title"]
+ @L["wa.install.lede"]
+
+ @L["wa.install.web.title"]
+
+ - @L.M("wa.install.web.1")
+ - @L.M("wa.install.web.2")
+ - @L.M("wa.install.web.3")
+
+
+ @L["wa.install.win.title"]
+ @L.M("wa.install.win.body")
+
+
+ @L["wa.install.size"]
+
+
+@* The differentiator, stated as a mechanism rather than a promise: there is no endpoint, so there
+ is nothing to send the document to. A claim a reader can check in the manifest beats one they
+ have to believe. *@
+
+ @L["wa.privacy.title"]
+ @L.M("wa.privacy.body")
+ @L.M("wa.privacy.permission")
+
+
+
+ @L["wa.does.title"]
+
+
+
+@* The refusal, with the numbers read from the shipped calibration. This is the part a teacher is
+ deciding about, so it gets its own section rather than a caveat at the bottom. *@
+
+ @L["wa.short.title"]
+ @L.F("wa.short.body", Floor)
+ @L.F("wa.short.quote", Floor)
+ @L.F("wa.short.rate", Texts, Flagged, RateHigh)
+ @L["wa.short.facts"]
+
+
+
+ @L["wa.not.title"]
+
+ - @L.F("wa.not.powerpoint", Floor)
+ - @L["wa.not.parts"]
+ - @L["wa.not.store"]
+
+
+
+
+
+@code {
+ private const string Repo = "https://github.com/peopleworks/SignsofAI/blob/main/src/SignsOfAI.Word";
+ private const string ManifestUrl = $"{Repo}/manifest.xml";
+ private const string StepsUrl = $"{Repo}/README.md";
+
+ // Same shape as Download.razor's list, and listed by hand in LocaleFileTests for the same
+ // reason: a text search cannot see a key built from this array.
+ private static readonly string[] Does = ["reads", "evidence", "characters", "languages"];
+
+ // Read, never restated. why.html was typed by hand and spent six days quoting a corpus of
+ // ninety after the corpus became 296.
+ private static int Floor => PublishedCalibration.Current?.ShortestWords ?? 0;
+ private static int Texts => PublishedCalibration.Current?.Texts ?? 0;
+ private static int Flagged => PublishedCalibration.Current?.FlaggedAtThreshold ?? 0;
+ private static string RateHigh =>
+ ((PublishedCalibration.Current?.RateHigh ?? 0) * 100).ToString("0.0");
+}
diff --git a/src/SignsOfAI.UI/wwwroot/css/app.css b/src/SignsOfAI.UI/wwwroot/css/app.css
index 83569e1..b5ce1cd 100644
--- a/src/SignsOfAI.UI/wwwroot/css/app.css
+++ b/src/SignsOfAI.UI/wwwroot/css/app.css
@@ -1101,6 +1101,39 @@ button.ghost.sm { padding: .35rem .7rem; font-size: .82rem; }
Deliberately shares the visual language of the front-door task cards: somebody who learned to
read those four cards reads these four the same way. */
.dl-h2 { font-size: 1.02rem; margin: 0 0 .35rem; }
+
+/* The Word add-in page. It reuses the download page's cards, and adds only what it needs:
+ a sub-heading inside a card, and a pulled quote for the sentence the pane actually prints. */
+.wa-h3 { font-size: .94rem; font-weight: 650; margin: 1.1rem 0 .4rem; }
+
+/* A row of links where one of them is the action. why.html has a .cta of its own — it is a
+ standalone page with its own stylesheet — and copying the markup here without the style is
+ exactly how this shipped as two bare links sitting against each other. */
+.cta { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; margin: 1rem 0 .4rem; }
+.cta a {
+ padding: .55rem 1rem;
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ text-decoration: none;
+ font-weight: 600;
+ font-size: .92rem;
+ transition: filter .15s, transform .15s, border-color .15s;
+}
+.cta a:hover, .cta a:focus-visible { transform: translateY(-1px); border-color: var(--brand); }
+.cta a.primary {
+ background: var(--brand);
+ color: var(--brand-ink);
+ border-color: transparent;
+}
+.cta a.primary:hover, .cta a.primary:focus-visible { filter: brightness(1.08); }
+.wa-quote {
+ margin: .6rem 0;
+ padding: .7rem .9rem;
+ border-left: 3px solid var(--muted, #9aa4b0);
+ background: rgba(128, 128, 128, .07);
+ font-size: .92rem;
+ line-height: 1.5;
+}
.dl-h2 svg { vertical-align: -2px; }
/* The call to action. A link, not a button, because it is a download and the browser should be
diff --git a/src/SignsOfAI.UI/wwwroot/i18n/en.json b/src/SignsOfAI.UI/wwwroot/i18n/en.json
index 9bf27bf..c461c63 100644
--- a/src/SignsOfAI.UI/wwwroot/i18n/en.json
+++ b/src/SignsOfAI.UI/wwwroot/i18n/en.json
@@ -59,12 +59,44 @@
"dl.same.body": "The same text gets the same number here and in the browser — it is the same engine, compiled from the same source. Nothing is uploaded to run the analysis. Four optional features can send text off the device and not one of them runs unless you turn it on; in the desktop app the perplexity measurement is local too, so three remain.",
"dl.word.title": "Inside Word, where the writing happens",
"dl.word.lede": "A task pane that reads the open document and answers in the sidebar. Same engine, same rules, same numbers — Word is simply a third place to run it.",
- "dl.word.why": "A task pane is a browser, so the engine runs there, on your machine, and the document is never uploaded. Every other add-in of this kind posts your text to an API, because their analysis is a server; ours is not, so there is nothing to post it to. And it asks Word for permission to read your document, never to change it — Word enforces that, rather than asking you to trust a sentence on a website.",
- "dl.word.install.web": "Word on the web: Home → Add-ins → More Add-ins → My Add-ins → Upload My Add-in, and choose the manifest.",
- "dl.word.install.desktop": "Word for Windows has no upload button and reads a shared folder instead; the steps are written out in the add-in's own page.",
- "dl.word.manifest": "The manifest",
- "dl.word.steps": "Installing, step by step",
- "dl.word.size": "First load is about 3.4 MB — the runtime, cached afterwards. Not in the Office Store yet.",
+ "wa.pagetitle": "Word add-in — Signs of AI Writing",
+ "wa.h1": "Signs of AI Writing, inside Word",
+ "wa.tagline": "A task pane that reads the document you have open and answers beside it. Same engine, same rules, same numbers — and the document never leaves your machine.",
+ "wa.install.title": "Installing it",
+ "wa.install.lede": "There is nothing to download and nothing to run. Word loads the pane from a web address; what you install is a small manifest file that tells it which one.",
+ "wa.install.web.title": "Word on the web",
+ "wa.install.web.1": "Open a document at office.com.",
+ "wa.install.web.2": "Home → Add-ins → More Add-ins → My Add-ins → Upload My Add-in.",
+ "wa.install.web.3": "Choose the manifest below. Then Home → Read the signs.",
+ "wa.install.win.title": "Word for Windows",
+ "wa.install.win.body": "The desktop version has no upload button. It reads a shared folder you register once in Trust Center, and after that the add-in appears in the ribbon like any other. It is more clicks than it should be, and that is Microsoft's design rather than ours — the steps are written out in full on the add-in's page.",
+ "wa.install.manifest": "Get the manifest",
+ "wa.install.steps": "Installing, step by step",
+ "wa.install.size": "First load is about 3.4 MB — the .NET runtime, cached afterwards. Not in the Office Store yet, which is why installing it still takes a menu.",
+ "wa.privacy.title": "Your document is never uploaded",
+ "wa.privacy.body": "Not as a promise — as a mechanism. A task pane is a browser: an embedded window with the same rules as a tab. The engine is WebAssembly, it downloads once with the pane, and it runs there. There is no endpoint in this add-in, so there is nowhere for your text to be sent. Every other add-in of this kind posts your document to a server, because their analysis is the server.",
+ "wa.privacy.permission": "And it asks Word for permission to read your document, never to change it. That is one line in the manifest, and Word enforces it — you do not have to take our word for it, and you can read the line yourself before installing anything.",
+ "wa.does.title": "What it does",
+ "wa.does.reads.name": "Reads the open document",
+ "wa.does.reads.what": "One button. No copying into a browser, no saving a file first, no leaving the page you are writing on.",
+ "wa.does.evidence.name": "Names every signal",
+ "wa.does.evidence.what": "Not a percentage on its own. Each tell is listed by name with the fix, so you can disagree with any one of them.",
+ "wa.does.characters.name": "Finds what typing cannot produce",
+ "wa.does.characters.what": "Invisible characters and letters from other alphabets, with the codepoint and every position. A fact about the file, not a judgement of its prose.",
+ "wa.does.languages.name": "English and Spanish",
+ "wa.does.languages.what": "The pane's language and the document's are independent. A Spanish essay is judged by Spanish rules, whichever language you read the interface in.",
+ "wa.short.title": "What it does with a short document, which is the part worth reading",
+ "wa.short.body": "It gives a score and then declines to draw a conclusion from it. The boundary this build judges by was measured only on documents of {0} words and longer, so below that length there is nothing it was fitted on. The pane says so:",
+ "wa.short.quote": "No verdict at this length. The boundary was measured only on texts of {0} words and longer, so no verdict is given — the score is neither evidence that a machine wrote this nor evidence that a person did.",
+ "wa.short.rate": "The boundary itself was measured on {0} documents written before 2022 — human by their dates, not by anyone's opinion. At that boundary it flags {1} of them, and the honest upper bound is {2}%. That figure is published, and it moves when the corpus moves.",
+ "wa.short.facts": "The character scan and the citation cross-check carry no threshold, so they still report at any length. Most of what people check is a paragraph, so the pane will decline often. That is the design, not a gap in it.",
+ "wa.not.title": "What it does not do",
+ "wa.not.powerpoint": "There is no PowerPoint version. A slide deck rarely reaches {0} words, so the same add-in there would withhold the verdict for almost every deck — correctly, and to nobody's benefit. That is a different product with a different promise.",
+ "wa.not.parts": "It reads the body of the document. Not comments, not footnotes, not tracked changes.",
+ "wa.not.store": "It is not in the Office Store yet, so installing it is a manifest and a menu rather than a button.",
+ "wa.cta.try": "Try it in the browser first",
+ "wa.cta.code": "Read the code",
+ "nav.word": "Word",
"dl.warn.title": "Windows will warn you, and it is right to",
"dl.warn.body": "The download is not code-signed — a certificate is the one thing this project has no funding for. SmartScreen therefore says Windows protected your PC the first time you run it, and names an unknown publisher. The warning is doing its job. Check the file instead of clicking through it:",
"dl.warn.step1": "Right-click the downloaded .zip → Properties, and tick Unblock if it is offered.",
@@ -449,5 +481,6 @@
"home.report.hint": "A document you can keep, forward or print. It contains your text, so it is saved to your device.",
"home.report.title": "Writing analysis report",
"batch.report.hint": "Save the scan as a document you can keep or hand to a colleague. It names your students' files.",
- "batch.report.title": "Folder scan — reading order"
+ "batch.report.title": "Folder scan — reading order",
+ "dl.word.page": "How it works, and how to install it"
}
diff --git a/src/SignsOfAI.UI/wwwroot/i18n/es.json b/src/SignsOfAI.UI/wwwroot/i18n/es.json
index 3e2e79a..7174bb1 100644
--- a/src/SignsOfAI.UI/wwwroot/i18n/es.json
+++ b/src/SignsOfAI.UI/wwwroot/i18n/es.json
@@ -59,12 +59,44 @@
"dl.same.body": "El mismo texto obtiene el mismo número aquí y en el navegador — es el mismo motor, compilado de la misma fuente. No se sube nada para hacer el análisis. Hay cuatro funciones opcionales que pueden enviar texto fuera del dispositivo y ninguna se activa si tú no la activas; en la app de escritorio la medición de perplejidad también es local, así que quedan tres.",
"dl.word.title": "Dentro de Word, donde se escribe",
"dl.word.lede": "Un panel que lee el documento abierto y responde en la barra lateral. El mismo motor, las mismas reglas, los mismos números — Word es sencillamente un tercer sitio donde ejecutarlo.",
- "dl.word.why": "Un panel de tareas es un navegador, así que el motor corre ahí, en tu máquina, y el documento no se sube a ningún sitio. Los demás add-ins de este tipo envían tu texto a una API, porque su análisis es un servidor; el nuestro no lo es, así que no hay adónde enviarlo. Y le pide permiso a Word para leer el documento, nunca para cambiarlo — lo impone Word, en vez de pedirte que te fíes de una frase en una web.",
- "dl.word.install.web": "Word en el navegador: Inicio → Complementos → Más complementos → Mis complementos → Cargar mi complemento, y elige el manifest.",
- "dl.word.install.desktop": "Word para Windows no tiene botón de carga y lee una carpeta compartida; los pasos están escritos en la página del propio add-in.",
- "dl.word.manifest": "El manifest",
- "dl.word.steps": "Cómo instalarlo, paso a paso",
- "dl.word.size": "La primera carga son unos 3,4 MB — el runtime, y después queda en caché. Todavía no está en la tienda de Office.",
+ "wa.pagetitle": "Complemento de Word — Signs of AI Writing",
+ "wa.h1": "Signs of AI Writing, dentro de Word",
+ "wa.tagline": "Un panel que lee el documento que tienes abierto y responde al lado. El mismo motor, las mismas reglas, los mismos números — y el documento no sale de tu máquina.",
+ "wa.install.title": "Cómo se instala",
+ "wa.install.lede": "No hay nada que descargar ni nada que ejecutar. Word carga el panel desde una dirección web; lo que instalas es un archivo pequeño, el manifest, que le dice cuál.",
+ "wa.install.web.title": "Word en el navegador",
+ "wa.install.web.1": "Abre un documento en office.com.",
+ "wa.install.web.2": "Inicio → Complementos → Más complementos → Mis complementos → Cargar mi complemento.",
+ "wa.install.web.3": "Elige el manifest de abajo. Después Inicio → Read the signs.",
+ "wa.install.win.title": "Word para Windows",
+ "wa.install.win.body": "La versión de escritorio no tiene botón de carga. Lee una carpeta compartida que se registra una vez en el Centro de confianza, y a partir de ahí el complemento aparece en la cinta como cualquier otro. Son más clics de los que debería, y el diseño es de Microsoft y no nuestro — los pasos están escritos enteros en la página del complemento.",
+ "wa.install.manifest": "Descargar el manifest",
+ "wa.install.steps": "Cómo instalarlo, paso a paso",
+ "wa.install.size": "La primera carga son unos 3,4 MB — el runtime de .NET, y después queda en caché. Todavía no está en la tienda de Office, y por eso instalarlo sigue siendo un menú.",
+ "wa.privacy.title": "Tu documento no se sube a ningún sitio",
+ "wa.privacy.body": "No como promesa, sino como mecanismo. Un panel de tareas es un navegador: una ventana incrustada con las mismas reglas que una pestaña. El motor es WebAssembly, se descarga una vez con el panel y corre ahí. En este complemento no hay ningún endpoint, así que no hay adónde mandar tu texto. Cualquier otro complemento de este tipo manda tu documento a un servidor, porque su análisis es el servidor.",
+ "wa.privacy.permission": "Y le pide a Word permiso para leer tu documento, nunca para cambiarlo. Es una línea del manifest, y la impone Word — no tienes que fiarte de nuestra palabra, y puedes leer esa línea tú mismo antes de instalar nada.",
+ "wa.does.title": "Qué hace",
+ "wa.does.reads.name": "Lee el documento abierto",
+ "wa.does.reads.what": "Un botón. Sin copiar a un navegador, sin guardar el archivo antes, sin salir de la página que estás escribiendo.",
+ "wa.does.evidence.name": "Nombra cada señal",
+ "wa.does.evidence.what": "No un porcentaje a secas. Cada indicio va con su nombre y su arreglo, así que puedes discrepar de cualquiera de ellos.",
+ "wa.does.characters.name": "Encuentra lo que no se teclea",
+ "wa.does.characters.what": "Caracteres invisibles y letras de otros alfabetos, con el punto de código y todas sus posiciones. Un hecho sobre el archivo, no un juicio sobre su prosa.",
+ "wa.does.languages.name": "Inglés y español",
+ "wa.does.languages.what": "El idioma del panel y el del documento son independientes. Un ensayo en español se juzga con reglas españolas, leas la interfaz en el idioma que la leas.",
+ "wa.short.title": "Qué hace con un documento corto, que es la parte que conviene leer",
+ "wa.short.body": "Da una puntuación y después se niega a sacar una conclusión de ella. La frontera con la que juzga esta versión se midió solo sobre documentos de {0} palabras o más, así que por debajo de esa longitud no hay nada sobre lo que se haya ajustado. El panel lo dice:",
+ "wa.short.quote": "Sin veredicto a esta longitud. La frontera se midió solo sobre textos de {0} palabras o más, así que aquí no se da veredicto: la puntuación no es prueba de que lo escribiera una máquina ni prueba de que lo escribiera una persona.",
+ "wa.short.rate": "La frontera se midió sobre {0} documentos escritos antes de 2022 — humanos por su fecha, no por la opinión de nadie. En esa frontera marca {1} de ellos, y la cota alta honesta es del {2} %. Esa cifra está publicada y se mueve cuando se mueve el corpus.",
+ "wa.short.facts": "El escáner de caracteres y el contraste de la bibliografía no llevan umbral, así que siguen informando a cualquier longitud. Casi todo lo que la gente comprueba es un párrafo, así que el panel se va a callar a menudo. Eso es el diseño, no un hueco en él.",
+ "wa.not.title": "Qué no hace",
+ "wa.not.powerpoint": "No hay versión para PowerPoint. Una presentación casi nunca llega a {0} palabras, así que el mismo complemento ahí retendría el veredicto con casi cualquiera — correctamente, y sin servirle a nadie. Es otro producto con otra promesa.",
+ "wa.not.parts": "Lee el cuerpo del documento. No los comentarios, ni las notas al pie, ni el control de cambios.",
+ "wa.not.store": "Todavía no está en la tienda de Office, así que instalarlo es un manifest y un menú en vez de un botón.",
+ "wa.cta.try": "Probarlo antes en el navegador",
+ "wa.cta.code": "Ver el código",
+ "nav.word": "Word",
"dl.warn.title": "Windows te va a avisar, y hace bien",
"dl.warn.body": "La descarga no está firmada — un certificado es justo lo que este proyecto no puede costear. Por eso SmartScreen dice Windows protegió su PC la primera vez y habla de un editor desconocido. El aviso está haciendo su trabajo. Comprueba el archivo en vez de saltártelo:",
"dl.warn.step1": "Clic derecho en el .zip descargado → Propiedades, y marca Desbloquear si aparece.",
@@ -449,5 +481,6 @@
"home.report.hint": "Un documento para guardar, reenviar o imprimir. Contiene tu texto, así que se guarda en tu dispositivo.",
"home.report.title": "Reporte de análisis de escritura",
"batch.report.hint": "Guarda el análisis como un documento para conservar o pasar a un colega. Nombra los archivos de tus estudiantes.",
- "batch.report.title": "Análisis de carpeta — orden de lectura"
+ "batch.report.title": "Análisis de carpeta — orden de lectura",
+ "dl.word.page": "Cómo funciona y cómo se instala"
}
diff --git a/tests/SignsOfAI.Core.Tests/LocaleFileTests.cs b/tests/SignsOfAI.Core.Tests/LocaleFileTests.cs
index b51404a..06b3542 100644
--- a/tests/SignsOfAI.Core.Tests/LocaleFileTests.cs
+++ b/tests/SignsOfAI.Core.Tests/LocaleFileTests.cs
@@ -40,6 +40,9 @@ .. Enum.GetValues().Select(s => "sev." + s.ToString().ToLowerInvariant
// Download.razor builds these from its own list, the same way.
.. new[] { "documents", "folder", "perplexity", "ollama" }
.SelectMany(a => new[] { $"dl.add.{a}.name", $"dl.add.{a}.what", $"dl.add.{a}.browser" }),
+ // WordAddin.razor builds these from its own list, the same way Download.razor does.
+ .. new[] { "reads", "evidence", "characters", "languages" }
+ .SelectMany(d => new[] { $"wa.does.{d}.name", $"wa.does.{d}.what" }),
// Chosen by the host at startup — HostCapabilities.RuntimeKey — so the footer and the
// .NET badge's tooltip describe the runtime the reader is actually looking at.
"footer.runtime.browser", "footer.runtime.desktop",