theme.css generated from the design system — and 28 things it found #92

Merged
bvandeusen merged 2 commits from dev into main 2026-07-31 12:45:07 -04:00
Owner

Two commits, 473280e + 67a529a. CI green (run 3150). No migrations.

theme.css is now generated from design system 2 (Scribe, inheriting FabledSword) plus an alias layer, so the record decides the styling rather than describing it afterwards.

Visible changes to expect

Dark is the base layer. :root carries the dark palette; [data-theme="light"] overrides it. useTheme already set the attribute explicitly to "light" or "dark", so no JS changed. This also closes the one-way scoping gap #251 recorded — a container can now add light as well as dark.

Small colour shifts where a fallback had drifted — see below. Those shifts are the fix, not a regression.

What the audit found

12 dead tokens, removed. Declared in both modes, referenced by nothing — seven from the removed chat subsystem, plus --glow-soft, --color-action-ghost-border, --radius-pill and two chat widths. 17% of the file styled a feature that no longer exists.

16 names referenced but never declared — not by this change; they were never in the file. Fourteen carried hardcoded fallbacks, so nothing failed and nothing looked broken, but the fallback was what rendered every time:

reference what actually rendered
--color-primary-bg rgba(99,102,241,0.15) — an indigo
--color-destructive #b85a4a — not the oxblood
--color-status-cancelled #6b7280 — a grey from no palette here
--color-muted #888

All 16 now resolve to real tokens. A fallback is worse than a missing token, because it looks fine.

Two tokens the app needed and never had: --fs-status-cancelled and --fs-layout-header.

Structural result

60 dark overrides became 12 — the other 48 restated relationships the derivations now express. Scribe's domain semantics (status, priority, overdue, wikilink) are all derived from family colours: twelve rows of duplicated hex became twelve formulas and zero new values.

95 tokens resolved, none valueless, 34 derived, no broken references, no cycles.

Also in 473280e: product copy no longer teaches one install's kit — placeholders and docstring examples describe the shape rather than naming FabledSword.

Two commits, `473280e` + `67a529a`. CI green (run 3150). No migrations. `theme.css` is now generated from design system 2 (Scribe, inheriting FabledSword) plus an alias layer, so the record decides the styling rather than describing it afterwards. ## Visible changes to expect **Dark is the base layer.** `:root` carries the dark palette; `[data-theme="light"]` overrides it. `useTheme` already set the attribute explicitly to `"light"` or `"dark"`, so no JS changed. This also closes the one-way scoping gap #251 recorded — a container can now add light as well as dark. **Small colour shifts where a fallback had drifted** — see below. Those shifts are the fix, not a regression. ## What the audit found **12 dead tokens, removed.** Declared in both modes, referenced by nothing — seven from the removed chat subsystem, plus `--glow-soft`, `--color-action-ghost-border`, `--radius-pill` and two chat widths. 17% of the file styled a feature that no longer exists. **16 names referenced but never declared** — not by this change; they were never in the file. Fourteen carried hardcoded fallbacks, so nothing failed and nothing looked broken, but the fallback was what rendered every time: | reference | what actually rendered | |---|---| | `--color-primary-bg` | `rgba(99,102,241,0.15)` — an indigo | | `--color-destructive` | `#b85a4a` — not the oxblood | | `--color-status-cancelled` | `#6b7280` — a grey from no palette here | | `--color-muted` | `#888` | All 16 now resolve to real tokens. A fallback is worse than a missing token, because it looks fine. **Two tokens the app needed and never had:** `--fs-status-cancelled` and `--fs-layout-header`. ## Structural result 60 dark overrides became 12 — the other 48 restated relationships the derivations now express. Scribe's domain semantics (status, priority, overdue, wikilink) are all derived from family colours: twelve rows of duplicated hex became twelve formulas and zero new values. 95 tokens resolved, none valueless, 34 derived, no broken references, no cycles. Also in `473280e`: product copy no longer teaches one install's kit — placeholders and docstring examples describe the shape rather than naming FabledSword.
bvandeusen added 2 commits 2026-07-31 12:44:57 -04:00
chore(design-systems): stop teaching one install's kit in product copy
CI & Build / Python lint (push) Successful in 5s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / integration (push) Successful in 27s
CI & Build / TypeScript typecheck (push) Successful in 36s
CI & Build / Python tests (push) Successful in 49s
CI & Build / Build & push image (push) Successful in 41s
473280e690
The operator's check: this must be a system for managing design systems, not one
with the FabledSword family built into it.

No LOGIC was coupled — the audit found zero behavioural dependencies. But every
docstring example, every UI placeholder and several comments named this install's
palette, so a stranger creating their first design system was shown
"FabledSword" as the expected shape and `--fs-obsidian` as the expected token.
Examples teach, and these taught the wrong thing.

Placeholders now describe the SHAPE ("Your house style", "--surface-page")
rather than naming one instance's contents, and the token-name placeholder now
says the thing worth saying: name it for its purpose, because `--obsidian` and
`--button-bg` both stop being true the moment the value or the element changes.

Not fixed here, and it is the one real coupling left: DesignView.vue hardcodes
rule 65's button variants and rule 60's type scale as literal arrays, so a
stranger's Design page would display this family's specs. Those arrays exist
because there was no design system to read from — which there now is. They go
when the panel is repointed (#2295), not before.

Scribe's own stylesheet comments ("Moss action-primary per Hybrid") are left
alone: that is the app CONSUMING the family style, which is what dogfooding
looks like, not the tool assuming it.
feat(theme): repoint theme.css at the design system, and find what wasn't captured
CI & Build / Python lint (push) Successful in 5s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 32s
CI & Build / TypeScript typecheck (push) Successful in 34s
CI & Build / Python tests (push) Successful in 53s
CI & Build / Build & push image (push) Successful in 42s
67a529a38e
theme.css is now generated from design system 2 (Scribe, inheriting FabledSword)
plus a compatibility alias layer, so the record decides the styling rather than
describing it after the fact.

**Dark is now the base layer.** The kit is dark-mode-first, so `:root` carries
the dark palette and `[data-theme="light"]` overrides it — the inverse of how
this file read before. `useTheme` already sets the attribute explicitly to
"light" or "dark", so the flip needed no JS change. It also closes the one-way
scoping gap #251 recorded: there IS a `[data-theme="light"]` block now, so a
container can add light as well as dark.

**60 dark overrides became 12.** The other 48 were restating relationships the
derivations now express: `--color-bg` follows `--fs-surface-page` because an
alias resolves at use time, so it needs stating once rather than per mode.

## What the audit found, which is the actual deliverable

**12 dead tokens, removed.** Declared in both modes, referenced by nothing:
seven from the removed chat subsystem (bubbles, input bar), plus `--glow-soft`,
`--color-action-ghost-border`, `--radius-pill` and two chat widths. 17% of the
file was styling a feature that no longer exists.

**16 names referenced but NEVER declared** — not by this change, not by the file
before it. Fourteen carried hardcoded fallbacks, so pages rendered and nothing
ever failed, but the fallback was what rendered, every time. Several were off
the palette entirely:

  --color-primary-bg      fell back to rgba(99,102,241,0.15) — an indigo
  --color-destructive     fell back to #b85a4a — not the oxblood
  --color-status-cancelled fell back to #6b7280 — a grey from no palette here
  --color-muted           fell back to #888

All 16 now resolve to real tokens. Expect small visual shifts exactly where a
fallback had drifted; the shift is the fix.

**Two tokens the app needed and never had**: `--fs-status-cancelled` (Scribe has
had a cancelled task status since the lifecycle was built and never had a colour
for it) and `--fs-layout-header` (referenced with a 52px fallback, so 52px was
always the real value — just not one anybody could look up).

## The system grew to cover what the app improvised

Per the operator: the kit wasn't growing with the app, and this is the result.
Recorded as tokens with GAP RECORDED FROM PRACTICE in their rationale — action
hover states, disabled opacity, the modal scrim, both code backgrounds, the
table stripe, the CTA gradient and glows, the accent-deep and accent-wash tints,
and the layout dimensions.

Scribe's own system gained its domain semantics — task status, priority, overdue,
wikilink — all DERIVED from family colours, so twelve rows of duplicated hex
became twelve formulas and zero new values. Priority maps onto the semantic
ladder deliberately: low is info, medium is warning, high is error.

95 tokens resolved, none valueless, 34 derived, no broken references, no cycles.
bvandeusen merged commit 716f227bc7 into main 2026-07-31 12:45:07 -04:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/FabledScribe#92