- name
- d3-f-styles
- description
- Styles — how d2 looks and how to change it: Style topics, the core Style:Base, the shared controls, the stylesheet for apps and embeds, Appearance, the look rules. Get skills only from /api/v2/skills/d3.
- feature
- styles
- concepts
- [style, control, appearance]
- tags
- #skill #feature #d3skill #wip
d3-f-styles¶✎ edit
Intro¶✎ edit
Looks are topics: style tokens and shared controls.
A look in d2 is a topic, never code: Style: topics hold style tokens, Style:Base on base d2 is the default, and a project layers its own on top — changing a look needs no coder and no deploy. Every page draws from one shared set of controls, and a person's Appearance (text size, width) scales it all. Pages and embeds are d3-f-pages; drafts d3-f-drafts. Spec: SpecUi › ui-core-style, SpecUi › ui-conventions (^ctl-n), Spec › settings (^appear-n).
Essentials¶✎ edit
- R-style-1 A look is a
Style:topic taggedstyle, never code; the cascade isStyle:Base, then the project's own Style topics. - R-style-2 MUST draw from the tokens (
var(--ink)), NEVER a hex, so every stylesheet and dark mode work. - R-style-3 One look per kind of control, everywhere: a page places and sizes its controls, NEVER restyles them.
- R-style-4 Every font size is
calc(<n>px*var(--fz,1))so text size applies; text fields never under 16 px. - R-style-5 An app or embed links
/styles/current.css, never copies colours by hand.
Concepts¶✎ edit
style¶✎ edit
A stylesheet: a Style:<name> topic tagged style with a ```style block of tokens. **Also called:** theme, look, stylesheet, skin.
**Fields (frontmatter):** name, description, brand (top-bar logo text, 1–24 chars, default diesel), base (stylesheet-orange1 default, or stylesheet-blue1), fonts (a https://fonts.googleapis.com/css2?family=… URL).
**Tokens:** --paper page background, --card cards and panels, --line borders; --ink main text, --soft secondary; --indigo / --indigo-bg the accent (links, highlights, the chosen item; any hue); --slate / --slate-bg second accent and code background; --sun / --sun-bg logo disc, drafts, notices; --leaf success; --rose / --rose-bg errors; --display, --body, --mono font stacks.
style_list¶✎ edit
- Summary: see the built-ins and the Style topics.
- When: before writing a style; when a project looks wrong.
- Needs: —
- Call:
GET /api/v2/styles· the page/styles. - Rules: —
- Errors: —
- Gotchas: —
style_write¶✎ edit
- Summary: a project's own look is a
Style:topic of tokens. - When: your person wants their own colours, fonts or logo text.
- Needs: the colours/fonts they want.
- Call: save
Style:<name>with frontmatter and a```styleblock of--token: valuelines → replystyle: {ok, errors}. - Rules: One
styleblock sets light and dark alike; add a```style darkblock only for tokens that differ in dark. A token you don't set comes frombase. Values are colours (#hex,rgb(…), names) or font stacks only — nourl(…),;,{,}; a web font goes infonts:and is named in--displayor--body. A whole new look sets at least--paper,--card,--ink,--soft,--line, readable on page and cards. Not ok → fix and save again. Then send your person to/styles(Style topics → Use this stylesheet). - Errors:
style: {ok: false, errors}→ fix the named token. - Gotchas: A Style topic with errors can't be picked, so it never breaks a page.
style_editBase¶✎ edit
- Summary: change d2's default look in
Style:Base, not in code. - When: the look of d2's own pages (titles, controls, chips) changes.
- Needs: —
- Call: a draft of
Style:Baseon base d2 → publish. - Rules: Editing it restyles everything that doesn't override it, on publish, with no build or deploy. In-code CSS is only
Style:Base's seed and the fallback if it can't be read.Style:Basemay be published as needed so your person can see the change; other base-d2 drafts wait for their publish. A look decision that is a rule is recorded in the spec; a small tweak lives only in the topic's history.<style>inside a topic is stripped, and a project's ownStyle:topic is a token theme whose rules don't reach other pages: a rule every page needs goes inStyle:Base's css block, scoped to what it styles ([data-block="connect-ai"] …). Style a block from its real markup in every state (log in as a person and click through), then check each state on your person's screen. - Errors: —
- Gotchas: —
style_link¶✎ edit
- Summary: apps and embeds link
/styles/current.css. - When: an
App:page or an embed. - Needs: —
- Call:
<link rel="stylesheet" href="/styles/current.css">→ the CSS an ordinary page inlines for this viewer (the chosen Style's tokens for light and dark, the base rules, the viewer's text size as:root{--fz:…}). - Rules: R-style-5, R-style-4. Open to visitors, cached per Style, text size and build (
ETag, 304). Screen width isn't carried (Wide is a selector on the page's own<html>): size an app's layout yourself. - Errors: —
- Gotchas: —
style_diagnose¶✎ edit
- Summary: a project looking wrong is usually its picked Style topic.
- When: a person says the look is wrong.
- Needs: —
- Call:
/styles(orstyle_list) before touching anything. - Rules: Usually its own Style topic is picked, or one with errors. A Style topic missing from Use this stylesheet has errors: open it and read the save's errors.
- Errors: —
- Gotchas: —
control¶✎ edit
A shared kind of control with one look everywhere. Also called: widget, button style, component. Kinds:
- Buttons: every
<button>and.btn;.primary(the page's main action),.danger,.on(pressed),.sm(also on a row: sizes every button in it),.lg. - Switches:
<button aria-pressed>, a track and knob before its label, never like an action; together, after the actions. - Icon buttons:
.ibtn, a bare glyph, no box (×, a fold). - Dropdowns:
select(.sm); a picker shows the current value (data-now), its apply button disabled until the pick differs; a coloured dot (risk levels) needs a custom picker — native dropdowns can't show one on iPad. - Tabs:
.tabbar, pills moving between pages or panes, current one filled. - Segmented toggles:
.tabs(.tabs.sm), one choice of a few within a page, chosen segment tinted. - Info icons: a small round ?, blue on a pale blue circle, after what it explains; opens a small panel (a page title's: a brief and a Help link).
- Search fields: rounded, a magnifier inside.
- Data tables:
table.dtablein.dbox(scrolls sideways itself, never the page),.dfilterabove (input + n of m), sort on header tap (▴/▾), one-line cells with … and full text on hover; wired by the shareddtable.js. - Status chips:
ps-<status>classes, from the tokens.
control_use¶✎ edit
- Summary: use the shared classes; place and size, never restyle.
- When: any markup with controls.
- Needs: the kind's class.
- Call: markup with the classes above.
- Rules: R-style-3. NEVER page CSS setting font, padding, background, border, corners, shadow or colour on a shared control. Only exceptions: colours that carry a meaning (the Architect's purple, the admin's) and the named own kinds.
- Errors: browser-default controls on a page → markup doesn't use the shared kinds (a
buttonrestyled locally, adivas a button): use the shared classes. - Gotchas: A page with browser-default buttons beside styled ones is a regression.
control_addKind¶✎ edit
- Summary: a new kind or own kind is a design call, not a builder's choice.
- When: no shared kind fits.
- Needs: a design ruling.
- Call: a new shared kind goes into the shared stylesheet and the guard test; an own kind is named in the guard test with why.
- Rules: A control only one page has keeps its own look and is named in the guard test (the level cards, the navbar's sync, the user menu's rows…).
- Errors: —
- Gotchas: —
control_guard¶✎ edit
- Summary: the guard test fails any page restyling a shared control.
- When: testing or reviewing UI.
- Needs: —
- Call: run the guard test and the shared-kinds test.
- Rules: The guard fails when a page stylesheet sets font, padding, background, border, corners, shadow or colour on a shared control outside the named own kinds; a second test checks the shared kinds exist.
- Errors: —
- Gotchas: —
appearance¶✎ edit
A person's display preferences, saved on the account. Also called: text size, zoom, wide mode.
Fields: fs Text size (Small · Normal · Medium · Large: html[data-fs] sets --fz 0.9 / 1.1 / 1.25), w Screen (Normal · Wide: html[data-w=wide]; prose stays ≤ 960 px).
appearance_set¶✎ edit
- Summary: text size and width per account, or per device.
- When: your person wants bigger text or a wider page.
- Needs: a signed-in person.
- Call:
/prefs#appearance·POST /prefs/look(formfs,w) →{ok, look}. - Rules: This device only overrides on one device. The server writes it on
<html>from thed2lookcookie, so pages don't jump. A page's intro line keeps--fz:1. The Contents column is a per-device toggle, not an Appearance setting. - Errors: 401
E_AUTH→ sign in · 403E_ORIGIN→ call from d2's own page · 400E_ARG→ a value other than the listed ones. - Gotchas: —
Rules¶✎ edit
Look rules for d2's own screens:
- R-style-6 Help is a little info icon, not a blurb: at most one muted intro line on a page (d3-f-help › help_onPage).
- R-style-7 The next step goes first: on an item page the person's logical next action (Seen, Run, Accept, Unpark…) is emphasised and leftmost; the rest follow, secondary.
- R-style-8 Property boxes on internal screens are compact and content-sized and don't follow Wide; Wide is for content.
- R-style-9 Forms: each label left of its control, compact rows.
- R-style-10 Role and level pickers show the same green/yellow/orange/red risk dot as the permission presets.
- R-style-11 Diagram snapshots are dark on a dark card, never on white.
- R-style-12 A new page matches earlier mockups and uses only shared kinds.
Errors¶✎ edit
style: {ok: false, errors}— a value that isn't a colour or font stack, or a forbidden character (url(,;,{,}) → fix the named token, save again. see #style_write- Style topic missing from Use this stylesheet — it has errors → read the save's errors. see #style_diagnose
- browser-default controls on a page — markup doesn't use the shared kinds → use the shared classes. see #control_use
E_AUTH(401) — not signed in. see #appearance_setE_ORIGIN(403) — the call didn't come from d2's own page. see #appearance_setE_ARG(400) — a value other than the listed ones. see #appearance_set