Version 1 of 1 · · razie · in person · Current version

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

Intro

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

  • R-style-1 A look is a Style: topic tagged style, never code; the cascade is Style: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

style

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

  • 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

  • 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 ```style block of --token: value lines → reply style: {ok, errors}.
  • Rules: One style block sets light and dark alike; add a ```style dark block only for tokens that differ in dark. A token you don't set comes from base. Values are colours (#hex, rgb(…), names) or font stacks only — no url(…), ;, {, }; a web font goes in fonts: and is named in --display or --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

  • 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:Base on 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:Base may 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 own Style: topic is a token theme whose rules don't reach other pages: a rule every page needs goes in Style: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: —
  • 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

  • Summary: a project looking wrong is usually its picked Style topic.
  • When: a person says the look is wrong.
  • Needs: —
  • Call: /styles (or style_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

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.dtable in .dbox (scrolls sideways itself, never the page), .dfilter above (input + n of m), sort on header tap (▴/▾), one-line cells with … and full text on hover; wired by the shared dtable.js.
  • Status chips: ps-<status> classes, from the tokens.

control_use

  • 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 button restyled locally, a div as a button): use the shared classes.
  • Gotchas: A page with browser-default buttons beside styled ones is a regression.

control_addKind

  • 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

  • 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

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

  • 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 (form fs, w) → {ok, look}.
  • Rules: This device only overrides on one device. The server writes it on <html> from the d2look cookie, 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 · 403 E_ORIGIN → call from d2's own page · 400 E_ARG → a value other than the listed ones.
  • Gotchas: —

Rules

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

  • 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_set
  • E_ORIGIN (403) — the call didn't come from d2's own page. see #appearance_set
  • E_ARG (400) — a value other than the listed ones. see #appearance_set