# Design decisions

This page is the map to *why* the standard works the way it does. The full reasoning lives in context, in a **Why** aside on the page each decision affects, so this page collects the short version with a link to where the detail lives.

:::note[Why keep this at all?]
A standard's *shape* is easy to read off the [schema](https://standard.mode.place/docs/reference/schema/) and [contract](https://standard.mode.place/docs/contract/); its *reasons* are not. Keeping them in one place is what lets someone extending the standard tell a load-bearing choice from an incidental one.
:::

## The premise

- **Intent-based, user-owned, visitor-first.** A look is described by the *job* a value does (`the background of a primary action`), saved to *your* account, and rendered *your* way over the app's, wherever you've expressed one. The obvious alternatives fall short: styling that lives inside the app leaves your preference behind the moment you leave it, and a flat color palette (the nearest prior art, [standard.site](https://standard.site), ships four color fields) is a palette, not a system that can tell an action from a warning from a surface. → [What is a mode?](https://standard.mode.place/docs/what-is-a-mode/)

## The data model

- **The expression is the record key; themes are self-contained.** Identity lives on the record key, not in an `expresses` field, because only the key enforces "one theme per concept per repo": the protocol can't check a constraint across records. An `expresses` field, string or array, can't guarantee that uniqueness. Splitting a theme into a separate *values* record plus a *binding* costs an extra write and dangles the whole group if the values are ever deleted. A same-collection *symlink* (`default → dark`) admits cycles and a privileged "canonical" record. A self-contained record sidesteps all three: it can't dangle or cycle, and resolving one is a single `getRecord`. → [Schema › the record key](https://standard.mode.place/docs/reference/schema/#placemodestandardtheme)
- **Reuse is the owner's tooling, not the protocol.** A look answering to several names is several self-contained copies, kept in sync by the author's build step. The network stores compiled artifacts, like published CSS, not a normalized database. → [Schema › the record key](https://standard.mode.place/docs/reference/schema/#placemodestandardtheme)
- **Per-aspect completeness.** Aspects are optional, but each present aspect is complete. Requiring all 33 intents would forbid a color-only or type-only look; allowing partial aspects would force a per-intent merge engine to reconcile two sources each filling in *some* of the variables. Complete-when-present avoids both. → [Schema › per-aspect completeness](https://standard.mode.place/docs/reference/schema/#placemodestandardtheme)
- **An `aspects` container, not top-level `color`/`typography`.** So a renderer emits everything under it as variables without guessing style from metadata. → [Schema › aspects](https://standard.mode.place/docs/reference/schema/#aspects)
- **Fonts are theme-level assets.** They render to document-global `@font-face`, not scoped variables, so they sit beside `aspects`, not inside typography. → [Schema › typographyAspect](https://standard.mode.place/docs/reference/schema/#typographyaspect)
- **Values are plain CSS strings.** Format-agnostic, no transform layer; a malformed value just doesn't render. → [Schema › from value to CSS](https://standard.mode.place/docs/reference/schema/#from-value-to-css)
- **An optional `displayName`, presentation only.** Identity and matching stay on the record key; the display name exists for galleries and pickers, the same shape `app.bsky.feed.generator` uses (a semantic rkey as identifier, a display name for presentation). An app never matches or dedupes on it. → [Schema › theme](https://standard.mode.place/docs/reference/schema/#placemodestandardtheme)
- **A thin profile.** Themes are a one-to-many collection, like posts, so they live in their own collection, not folded into the singleton profile. Your baseline look is simply the theme saved at the reserved key `default`, matched like any other concept, so there's no separate pointer field to keep in sync. → [Schema › profile](https://standard.mode.place/docs/reference/schema/#placemodestandardprofile)

## How looks resolve

- **A `data-mode` marker plus cascade layers, not scoped placement.** Boundaries are declared once at build time, so the viewer's look, which only arrives later, after sign-in, becomes one appended `<style>` the cascade routes: no per-scope runtime injection. Placement scoped to a DOM position instead would need a `<style>` injected at every scope root at the moment the viewer's look arrives. → [Contract › Rule 3](https://standard.mode.place/docs/contract/#rule-3--applying-a-look-to-a-scope)
- **A two-form `data-mode` grammar.** Bare expression *or* disjoint aspect-fragments, never mixed, so ordering can never matter. A value that lists several bare expressions would raise an immediate question (which one wins, and does order matter?) that the two-form grammar avoids by construction. → [Contract › Rule 4](https://standard.mode.place/docs/contract/#rule-4--selecting-one-aspect-instead-of-the-whole-look)
- **The aspect delimiter is `/`, a character outside the record-key charset.** No expression can ever contain the delimiter, so the parse is unambiguous by construction and no expression name needs reserving. A colon looks like a natural choice, but it's a legal rkey character: using it would need convention-only "avoid the colon" rules, reserved words for `color`/`typography`, and would still leave some valid keys unaddressable. → [Contract › Rule 4](https://standard.mode.place/docs/contract/#rule-4--selecting-one-aspect-instead-of-the-whole-look)
- **`:where()` keeps specificity flat; layers rank tiers, not peers.** So layer order alone decides, and multi-author feeds need containment because the layer can't separate peers. → [Contract › Rule 5](https://standard.mode.place/docs/contract/#rule-5--whose-look-wins-fill-through-not-conflict)
- **`@scope` for multi-author containment.** It bounds matching without adding specificity, so the layer contest (and viewer override) survives inside a scoped post. → [Contract › Rule 7](https://standard.mode.place/docs/contract/#rule-7--keeping-a-foreign-look-contained)
- **Fill-through, not conflict.** Each variable comes from the most-preferred source that sets it; the viewer's guaranteed override is the accountability valve. → [Contract › Rule 5](https://standard.mode.place/docs/contract/#rule-5--whose-look-wins-fill-through-not-conflict)

## Naming & growth

- **Expressions are a convention, not a registry.** An opaque string compared for equality; good ids converge by network effect. A canonical `/expressions.json` endpoint, a lexicon `knownValues` enum, or an AT-URI-referenced `expression` record would each read as authoritative, or add a resolution dependency a plain string doesn't need. → [Common expressions › a convention, not a registry](https://standard.mode.place/docs/reference/expressions/#coining-your-own)
- **One reserved word: `default`.** The viewer's baseline, designated by saving a theme at that key. → [Common expressions › the one reserved word](https://standard.mode.place/docs/reference/expressions/#the-one-reserved-word-default)
- **Additive growth; a frozen core.** The 33 intents were reviewed against the *Mise en Mode* book and frozen, since records can't be tightened once they're on the network. Likely additions like `letterSpacing`, density, and motion are deferred rather than pre-included: adding one later is a lossless optional field, while shipping it early would burden every theme with completeness for a value the book itself treats as unsettled. → [Schema › the core grows](https://standard.mode.place/docs/reference/schema/#from-value-to-css)

## Where the rest lives

- **Identity, hosting, and the protocol features leveraged**, the DID, PDS, Tangled/Netlify setup, blob-stored fonts, firehose discovery, OAuth, and the standard.site lineage, are in the [Colophon](https://standard.mode.place/docs/colophon/).