---
-tags: help, apps, pages, style
-order: 25
-description: making topics, app pages and HTML pages, and styling them (where CSS can go and where it can't)
+tags: deleteme
+description: DELETEME
---
-# Help: apps and pages
-
-How to make the things people see in a project: plain topics, pages that show data, live HTML, whole-page apps, and the look of them all. Each part says which tool to reach for and its limits.
-
-## Topics {#topics}
-
-- **A topic is a page of markdown.** Its id is `Category:name`, or just `name` for an ordinary page. Names use letters, digits, `-` and `_`.
-- **Write it:** `PUT /api/v2/topics/<name>` with the markdown as the body (`Content-Type: text/markdown`). A `PUT` replaces the whole topic, so read it, change it, write it back.
-- **New topics must be published.** Writing a new topic makes a draft nobody else can see: `POST /api/v2/drafts/<name>/publish` makes it live. Edits to existing topics follow the project's draft rules (a draft needs `If-Match: "none"` the first time, then `"d<n>"`).
-- **Check the answer.** `errors`, `domain` and `objects` in the reply must be empty; if not, fix and save again.
-- **Frontmatter** sits at the top between `---` lines: `tags:` (flat lower-case words, comma-separated), `description:`, and for special topics their own keys.
-- **Links:** `[[Topic]]`, `[[Topic#section]]`, `[[Category:name]]`, `[[target|label]]`.
-
-## Pages that show data {#data-pages}
-
-Most app pages need no HTML at all.
-
-- ```` ```table ```` shows a class's objects (`class:`, `columns:`, `totals:`, `sort:`, `filter:`, `color:`). Each row opens its edit form; **+ Add** makes a new one. Drawn with the page: reload for new data.
-- ```` ```cards ```` makes a row of tiles, one line each: `icon | title | link | text` (`soon` for one that isn't live). The first cards block under a home page's title is its app list.
-- **An app** is a `Spec:` topic (the model), its objects (often seeded from a `Story:` topic), a page with its table, and a card on `Home`.
-
-## Built-in blocks {#blocks}
-
-Some fences are drawn by d2 itself, because they show per-viewer data, change accounts, or carry a secret: ```` ```connect-ai ````, ```` ```next-step ````, ```` ```my-projects ```` and the like. A topic places them; it can't rebuild them in HTML (an embed can't use the viewer's session). To change how one **looks**, style it (below).
-
-## Live HTML in a page: embedhtml {#embedhtml}
-
-A ```` ```embedhtml ```` fence holds HTML, CSS and a `<script>`, run in a sandboxed frame inside the page.
-
-- Its CSS stays inside the frame: it styles the widget, never the page around it.
-- It gets the page's colours and fonts as variables (`var(--ink)`, `var(--card)`, `var(--line)`, `var(--soft)`…): use them so it matches.
-- It can `fetch` sources that allow any origin; it can't read the page, the person's session or the project's API as them. For the project's own data use a table.
-- Show a clear state when a source doesn't answer, never a blank.
-
-## Whole HTML pages: App topics {#app-topics}
-
-An `App:<name>` topic is a whole HTML page at `/app/<name>`, under the project's top bar: for a dashboard or a custom editor.
-
-- It runs sandboxed and reaches the project through `await d2.api(method, path, body)`, as the person looking at it (the project's `/api/v2` routes only).
-- Keep the data in objects and the logic in rules; the page shows and triggers.
-- `layout: full` in its frontmatter gives it the whole window (its own navigation, a small button home).
-
-## Styling: where CSS can go {#css}
-
-Learned restyling the Onboard your AI steps, 2026-10-04.
+# DELETEME
-- **`<style>` in a topic does nothing.** d2 strips it from the markdown when it draws the page, silently. (A home page's old "polish" block had never applied.)
-- **A project's own `Style:` topic is a theme, not a layer.** It sets the colour and font tokens in a ```` ```style ```` block (known tokens only: `--paper --card --ink --soft --line --indigo --indigo-bg --slate --slate-bg --sun --sun-bg --leaf --rose --rose-bg --god --god-bg --admin --admin-bg --attn --display --body --mono`), and a person picks it at `/styles`. Rules put in one don't reach other pages.
-- **Rules that every page gets live in `Style:Base` on base d2,** in its ```` ```css ```` block. Publishing it rebuilds `/styles/shared.css` (its `?h=` changes), which every page of every project loads: no coder, no deploy.
- - Because it reaches everything, **scope every rule** to the thing you're styling, e.g. `[data-block="connect-ai"] .btn{…}`, never a bare `h2` or `.btn`.
- - Shared rules can override a block's own behaviour: a base rule showed a form the block had marked `hidden`. Add `[data-block="…"] [hidden]{display:none!important}` when you restyle a block with hidden parts.
-- **Style what's really there.** Before writing CSS for a block, get its real markup in every state it has: a token or a visitor often sees a placeholder, not the block. Log in as a person, click through each state (for connect-ai: before Done, waiting, connected) and read the HTML. Then style its own classes (`.blk-step`, `.nextstep`, `.done`…).
-- **Restyle, don't rebuild.** CSS goes a long way on markup you can't change:
- - `order` (with `display:flex` on the block) puts steps back in order when the markup moves them;
- - `:has()` picks a part by what it contains (`.blk-step:has(details)`, `h3:has([data-reload-while])`);
- - `:last-of-type` finds the last step;
- - `::before` / `::after` add icons: an SVG as a `data:` URL background, animated with `@keyframes`;
- - always add `@media (prefers-reduced-motion:reduce){…animation:none}` for anything that moves.
- - What CSS can't do: change text baked into the markup (a heading's "1." stays text).
-- **Check every state after a change,** on the person's real screen: a squeezed button (`white-space:nowrap; flex:none`) or an un-hidden form only shows in one of them.
-- **Colours:** prefer the page's tokens (`var(--line)`, `var(--soft)`); a fixed hex is fine for an accent that must stay the same in every theme.
+DELETEME. Moved to [[CreatingApps]].