From 0c91ab026decd3f105ff1ff5f7474cbc56c0f495 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sun, 26 Apr 2026 10:51:38 -0400 Subject: [PATCH] docs: add FabledSword design system + Scribe iteration decisions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Captures the FabledSword baseline (verbatim from initial draft) plus the Scribe-specific decisions made during the first iteration pass: - Hybrid accent rule (accent reserved for brand moments + nav/cursor + tags/wikilinks/in-progress/focus rings; Moss/Bronze/Oxblood/Pewter for action buttons by default) - Light mode warm parchment (specific hex values pinned) - Status + priority palette extension table (status-paused added) - Typography: Inter for body, doc scale verbatim, two weights - Chat-bubble "Illuminated Transcript" pattern codified - Voice and tone: adopt principles, defer formal audit - Border philosophy: structural not decorative - Iconography: Lucide as source, strict 16/24 scale, 1.5/1 stroke - Warm gold accent dropped (dates → text-secondary, paused → Warning) Doc lives at docs/design-system.md. Polish pass (applying the system to existing UI) is a separate, deferred phase. Co-Authored-By: Claude Opus 4.7 --- docs/design-system.md | 534 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 534 insertions(+) create mode 100644 docs/design-system.md diff --git a/docs/design-system.md b/docs/design-system.md new file mode 100644 index 0000000..4ad6795 --- /dev/null +++ b/docs/design-system.md @@ -0,0 +1,534 @@ +# FabledSword Design System + +A house-style design system for the FabledSword family of self-hosted applications. FabledSword is the umbrella identity; individual apps share a common visual language but each carries its own signature accent color. + +## Brand model + +FabledSword is a **house style**, not a single brand. Apps share: + +- Typography +- Surfaces and dark-mode foundation +- Component shapes (pills, cards, buttons) +- Spacing system +- Semantic colors (success, warning, error, info) +- Action button colors (moss primary, bronze secondary) +- Voice and tone + +Each public app has its own **signature accent** used for: the wordmark, the app icon, active nav state, "you are here" indicators, cursor/selection color, and key brand moments. Accents do **not** appear on action buttons — those stay system-wide. + +## Aesthetic direction + +Modern mythic with heraldic restraint. Tech-forward execution, but the visual language borrows from manuscripts, heraldry, and forged objects rather than from gaming or fantasy iconography. Dark-mode-first because that's where these apps live. + +The reference points: a well-printed book, a well-kept armory, a steward's ledger. Not: a fantasy novel cover, a tabletop RPG character sheet, a Renaissance Faire poster. + +--- + +## Color system + +### Universal surfaces (dark mode foundation) + +| Token | Hex | Usage | +|---|---|---| +| Obsidian | `#14171A` | Page background, deepest surface | +| Iron | `#1E2228` | Card surfaces, raised elements | +| Slate | `#2C313A` | Hovered surfaces, secondary elevation | +| Pewter | `#3F4651` | Borders, dividers, ghost button outlines | + +### Universal text and parchment + +| Token | Hex | Usage | +|---|---|---| +| Parchment | `#E8E4D8` | Primary text on dark surfaces | +| Vellum | `#C2BFB4` | Secondary text, captions | +| Ash | `#9C9A92` | Tertiary text, hints, metadata | + +Parchment is intentionally not pure white — it's slightly warm to feel like aged paper. Pure white (#FFFFFF) is never used as text color. + +### Universal action colors + +| Token | Hex | Usage | +|---|---|---| +| Moss | `#4A5D3F` | Primary action buttons (Save, Submit, Confirm) | +| Bronze | `#8B7355` | Secondary action buttons (Cancel-but-not-destructive, alternate paths) | +| Pewter | `#3F4651` | Tertiary/ghost buttons | + +**Critical rule:** Action button colors are universal across all apps. A Save button in Scribe and a Save button in Minstrel look identical. Per-app accents do not appear on buttons. + +### Semantic colors + +| Token | Hex | Usage | +|---|---|---| +| Success | `#4A5D3F` | Success states (same as Moss — they're aligned by design) | +| Warning | `#8B6F1E` | Warnings, caution states | +| Error | `#C04A1F` | Error messages, validation failures | +| Info | `#3D5A6E` | Informational callouts | +| Destructive | `#6B2118` | Destructive action buttons (Delete, Remove, irreversible) | + +**Why error and destructive are different:** Error is the orange-red used in alerts and validation messages. Destructive (oxblood) is reserved for buttons that perform irreversible actions — it carries more weight precisely because it's used sparingly. Pair destructive buttons with an icon (trash, X) so color is reinforcement, not the only signal. + +### Per-app signature accents + +| App | Hex | Mood | +|---|---|---| +| Fabled Scribe | `#5B4A8A` | Dusty violet — ink, manuscripts | +| Minstrel | `#4A6B5C` | Forest teal — music, performance | +| Fabled Forge | `#8B5A2B` | Forge bronze — creation, craft | +| Roundtable | `#4A5D7E` | Slate blue — stewardship, infrastructure | +| FabledSword (umbrella) | `#6B2118` | Oxblood — house identity, ceremonial use only | + +**Accent usage rules:** +- The accent appears on the app's wordmark and icon. +- The accent indicates active/current state in nav (the selected page, the active tab). +- The accent is the cursor color and text-selection color in long-form surfaces (Scribe notes, Forge story drafts). +- The accent does NOT appear on primary or secondary action buttons. +- The accent does NOT appear in body text or chrome. +- One accent per app. Don't mix accents within a single app. + +### Color contrast + +All text-on-surface combinations meet WCAG AA at minimum. Parchment on Obsidian is the maximum-contrast pairing; Vellum on Iron is the lowest-contrast pairing still considered acceptable for body text. Ash is for hints only — never load-bearing information. + +--- + +## Typography + +### Type families + +| Family | Role | Source | +|---|---|---| +| Fraunces | Display, headings, wordmarks | Google Fonts | +| Inter | Body, UI, labels | Google Fonts | +| JetBrains Mono | Code, terminal output, monospaced data | Google Fonts | + +### Why this pairing + +Fraunces is a contemporary serif with personality — it has the warmth and authority of a book serif without feeling like costume. It signals "this is considered" without signaling "this is a fantasy product." Inter is the workhorse — neutral, ubiquitous, designed for screens, doesn't compete with the serif. JetBrains Mono is the natural choice for any developer-adjacent product and supports ligatures. + +### Type scale + +| Token | Size | Weight | Family | Usage | +|---|---|---|---|---| +| Display | 40px | 500 | Fraunces | App wordmark, hero text | +| H1 | 32px | 500 | Fraunces | Page titles | +| H2 | 24px | 500 | Fraunces | Section headings | +| H3 | 18px | 500 | Inter | Subsection headings, card titles | +| Body | 15px | 400 | Inter | Paragraphs, default text | +| Body small | 13px | 400 | Inter | Captions, metadata | +| Label | 12px | 500 | Inter | Buttons, form labels, badges | +| Code | 13px | 400 | JetBrains Mono | Inline code, code blocks | +| Tiny | 11px | 500 | Inter | Micro-labels (`UPPERCASE LETTERSPACED`) | + +### Typography rules + +- **Sentence case everywhere.** Never Title Case for headings, never ALL CAPS except for the Tiny micro-label style. +- **Two weights only:** 400 regular and 500 medium. Never 600 or 700 — they read heavy in dark mode. +- **Fraunces only at 18px and above.** Below that it loses too much detail and feels fragile. For h3 and below, use Inter. +- **Line height** 1.5 for body, 1.3 for headings, 1.7 for long-form reading surfaces (Scribe notes, Forge drafts). +- **Letter-spacing** at default for everything except the Tiny micro-label, which gets `0.08em` letter-spacing and uppercase styling. + +--- + +## Spacing and layout + +### Spacing scale (px) + +`4, 8, 12, 16, 20, 24, 32, 48, 64, 96` + +Use rem units for vertical rhythm in long-form content (paragraph spacing). Use px for component-internal spacing (padding, gaps). + +### Border radius + +| Token | Size | Usage | +|---|---|---| +| Small | 4px | Pills, tags, code spans | +| Medium | 8px | Buttons, inputs, small cards | +| Large | 12px | Cards, panels, modals | +| Extra large | 16px | Hero containers, major surfaces | + +### Borders + +- Default border: `0.5px solid Pewter` (#3F4651) +- Hovered/emphasized border: `0.5px solid Vellum` at 30% opacity +- Featured/active border: `2px solid [accent]` (only for emphasizing a selected card or active tab) + +The 0.5px default is deliberate — it reads as a hairline at most pixel densities and avoids the heavy "boxed-in" feeling that 1px+ borders create on dark backgrounds. + +--- + +## Components + +### Buttons + +| Variant | Background | Text | Border | +|---|---|---|---| +| Primary | Moss `#4A5D3F` | Parchment | None | +| Secondary | Bronze `#8B7355` | Parchment | None | +| Ghost | Transparent | Parchment | 0.5px Pewter | +| Destructive | Oxblood `#6B2118` | Parchment | None — pair with icon | + +Padding: `8px 16px` for default, `6px 12px` for compact, `10px 20px` for prominent. Border-radius: 8px. Font: Inter 12px/500 with default letter-spacing. + +### Pills and tags + +Used for tags, hashtags, code spans, status badges. Background is the accent color at ~15% opacity, text is the accent at full strength. Border-radius 4px, padding `2px 8px`, Inter 11px/500. + +In Scribe specifically, hashtags and tags use the dusty violet accent. In Minstrel, they'd use forest teal. The pattern is shared; the color follows the app. + +### Cards + +- Background: Iron (#1E2228) +- Border: 0.5px Pewter +- Border-radius: 12px +- Padding: 20px + +For featured/selected cards, swap to a 2px solid accent border. Don't change the background. + +### Inputs + +- Background: Obsidian (#14171A) — darker than the page surface to feel "inset" +- Border: 0.5px Pewter +- Border-radius: 8px +- Padding: 8px 12px +- Focus state: 2px solid accent ring (using `box-shadow: 0 0 0 2px [accent]` to avoid layout shift) + +### Code blocks + +- Background: Obsidian (#14171A) +- Border: 0.5px Pewter +- Border-radius: 8px +- Padding: 12px 16px +- Font: JetBrains Mono 13px/400 +- Inline code: same family, with 4px-radius pill background using the app accent at 15% opacity + +--- + +## The FabledSword lockup + +A small, persistent FS mark appears in the navigation chrome of every app — the way an Apple logo persists across macOS apps. This is the only place oxblood appears in normal app usage. + +**Specification:** +- 16-20px height in nav contexts +- Oxblood (#6B2118) on dark surfaces +- Positioned in the bottom-left of nav rails or top-left when there's no rail +- Hover/click reveals a small menu: link to other apps in the family, link to FabledSword.com, version info + +The lockup itself is a small heraldic mark — a stylized FS monogram — *not* a literal sword icon. We're avoiding sword imagery in app chrome because it would clash with the restrained, modern-mythic aesthetic. The wordmark "FabledSword" appears only on the umbrella site and in About/Settings dialogs. + +--- + +## Voice and tone + +The FabledSword voice is **understated mythic** — it borrows the register of stewardship, craft, and considered making, but never tips into roleplay or affectation. + +### Do + +- Use plain language for everything functional. ("Save", "Cancel", "Add note") +- Reserve flavored language for moments where the user is *waiting* or *failing* — loading states, empty states, error pages, 404s. +- Borrow vocabulary from craft and stewardship: "draft", "ledger", "kept", "set aside", "to come", "in progress", "abandoned". +- Be brief. The mythic register is undermined by verbosity. + +### Don't + +- Don't use thee/thou/thy or pseudo-archaic spelling. +- Don't address the user as "traveler", "wanderer", "adventurer", or any RPG-adjacent epithet. +- Don't use sword/blade/forge metaphors in error messages. ("Your save was forged successfully" — no.) +- Don't make the user feel like they're playing a game when they're just trying to use software. + +### Examples + +| Context | Plain | FabledSword voice | +|---|---|---| +| Empty list | "No items yet" | "Nothing kept here yet." | +| 404 | "Page not found" | "This page is not in the ledger." | +| Loading | "Loading..." | "Fetching..." (just keep it plain — the mythic note is reserved for moments with more space) | +| Save success | "Saved!" | "Saved." (plain — success doesn't need flavor) | +| Save error | "Error saving" | "Couldn't save. The change has been kept locally — try again in a moment." | +| Delete confirm | "Delete this?" | "Remove this from the ledger? This can't be undone." | + +The pattern: action-adjacent language stays plain; absence/failure/waiting gets the flavor. + +--- + +## Iconography + +### Style + +- Stroke-based, 1.5px stroke weight at 24px, 1px at 16px +- Rounded line caps and joins +- 24px or 16px grid +- Outline style by default; filled style only for active/selected states + +Use **Lucide** (https://lucide.dev) as the base icon set — it matches this style exactly and is open-source. Only commission custom icons for app-specific concepts that Lucide doesn't cover. + +### Don't + +- No filled icons in default UI (reserve for active states) +- No icon styles that mix stroke and fill chaotically +- No literal medieval imagery (swords, scrolls with curls, banners) in functional UI +- No emoji as icons + +--- + +## Per-app application + +### Fabled Scribe (#5B4A8A — dusty violet) + +A second-brain notes and task management tool. The accent appears in: the wordmark, hashtags and tag pills, the active nav item, text selection color, and the cursor in the editor. Notes are presented on Iron-surfaced cards with generous reading line-height. The hashtag system uses Scribe's accent for visual continuity. + +### Minstrel (#4A6B5C — forest teal) + +Self-hosted music. The accent appears on: now-playing indicators, active track highlights, the wordmark, equalizer/visualization elements. Album art dominates visually, so the accent should appear in chrome and metadata, never overlapping cover imagery. + +### Fabled Forge (#8B5A2B — forge bronze) + +Story-building and worldbuilding tool. The accent appears on: the wordmark, character/location/object markers in story trees, the editor cursor, "kept/canon" indicators distinguishing finalized story elements from drafts. This app benefits from Fraunces being used more aggressively — for entity titles, chapter headings, etc. + +### Roundtable (#4A5D7E — slate blue) + +Home server management. The accent appears on: the wordmark, healthy/online status indicators, the active dashboard panel border. Status colors here are critical — green for healthy, amber for warning, red (the orange-red error tone, not oxblood) for failed. The accent itself indicates "this is the panel I'm currently looking at." + +**Naming note:** "Roundtable" leans the wrong direction — its connotation is *equal participants in discussion* rather than *one steward managing a domain*. Consider "Steward" or "Castellan" if you revisit naming. Castellan in particular is good — it specifically means "the officer in charge of a castle." + +--- + +## Implementation notes + +### CSS custom properties + +```css +:root { + /* Surfaces */ + --fs-obsidian: #14171A; + --fs-iron: #1E2228; + --fs-slate: #2C313A; + --fs-pewter: #3F4651; + + /* Text */ + --fs-parchment: #E8E4D8; + --fs-vellum: #C2BFB4; + --fs-ash: #9C9A92; + + /* Action */ + --fs-moss: #4A5D3F; + --fs-bronze: #8B7355; + + /* Semantic */ + --fs-warning: #8B6F1E; + --fs-error: #C04A1F; + --fs-info: #3D5A6E; + --fs-oxblood: #6B2118; + + /* Typography */ + --fs-font-display: 'Fraunces', Georgia, serif; + --fs-font-body: 'Inter', system-ui, sans-serif; + --fs-font-mono: 'JetBrains Mono', ui-monospace, monospace; + + /* Layout */ + --fs-radius-sm: 4px; + --fs-radius-md: 8px; + --fs-radius-lg: 12px; + --fs-radius-xl: 16px; +} + +/* Per-app accent — set ONE of these on the root for each app */ +[data-app="scribe"] { --fs-accent: #5B4A8A; } +[data-app="minstrel"] { --fs-accent: #4A6B5C; } +[data-app="forge"] { --fs-accent: #8B5A2B; } +[data-app="roundtable"]{ --fs-accent: #4A5D7E; } +``` + +### Tailwind integration + +If using Tailwind, extend the theme with these tokens rather than relying on default colors. The default Tailwind palette will fight this system — you'll get drift back toward bright defaults if you don't lock down the palette explicitly. + +--- + +## What this kit deliberately does NOT include + +- **Logo files.** The lockup design is described conceptually but the actual mark needs to be drawn. Hire a designer or use Claude Design to iterate on a heraldic FS monogram. +- **Marketing site design.** This kit is for application UI. The umbrella marketing site (FabledSword.com) can use this system but will need additional patterns (hero layouts, feature grids, etc.). +- **Email templates.** Different constraints, different problem. +- **Print collateral.** Not in scope. +- **Mobile native app patterns.** This is web-first. iOS/Android conventions would override several choices here (button shapes, navigation patterns). + +--- + +*Last updated: April 25, 2026. Iterate as the family of apps grows.* + +--- + +# Scribe-specific decisions in progress + +> This section tracks decisions made while adapting the FabledSword baseline above for Scribe specifically. Items here are *in progress* — once they feel solid, they get folded into the main body of the document (either as Scribe-specific extensions in the per-app section, or as updates to the universal rules where Scribe's needs reveal a gap in the baseline). + +*Iteration started: 2026-04-26.* + +## Decisions made so far + +### Accent footprint — Hybrid rule (not Strict) + +The doc baseline says the per-app accent only appears on wordmark, active nav, cursor, and text selection — never on action buttons. Scribe currently uses indigo on essentially every interactive surface (CTAs, scrollbars, glows, borders, focus rings). Hard-cutting to the doc baseline would lose too much identity in one swing. + +**Hybrid rule:** the accent reserves a slightly larger footprint than the doc baseline, but still much smaller than today. + +- **Accent (dusty violet) lives on:** wordmark; active nav; cursor and text selection in editor surfaces; tags/pills/wikilinks; in-progress task badge; focus rings; **brand-moment CTAs** — chat Send, "Create note" empty-state CTA, journal Send, "Start journaling" empty-state. +- **Moss (sage-green primary) lives on:** Save / Submit / Confirm in forms and modals; generic affirmative actions where the button just means "do this thing" with no brand pretense. +- **Bronze (secondary):** Cancel-but-not-destructive, alternative paths. +- **Oxblood (destructive):** Delete / Remove (paired with an icon). +- **Pewter ghost:** tertiary actions, "later", "skip", "see also". + +**Rule of thumb:** if the user is engaging with a *Scribe-feature moment* (sending a chat, opening a fresh note, jumping into the journal), accent. If they're just *operating the software* (saving an edit, confirming a dialog), Moss. + +### Light mode — warm parchment, matched aesthetic + +The doc is dark-only. Scribe today supports both light and dark, and we keep both. The light mode is derived to *match* the dark mode aesthetic rather than defaulting to system white-and-ink. + +- Page background: in the `#F5F1E8` warm cream family (specific values TBD) +- Cards: near-white but slightly tinted +- Text: deep ink `#14171A` (mirroring Obsidian) +- Accent: same dusty violet `#5B4A8A` (works on both themes) + +The metaphor stays consistent across themes: ink on aged paper (light) ↔ parchment text on graphite (dark). Light mode is *not* the system standard look. + +**Known downside:** warm parchment backgrounds can fight with embedded color content. Mitigation: code blocks get a slight cool wash in light mode specifically, to keep syntax highlighting readable. + +### Status and priority palette — extend the doc's semantic set + +The doc's semantic colors (Success / Warning / Error / Info / Destructive) are leaner than what Scribe needs for task management. Rather than running a parallel palette, Scribe extends the doc by mapping its status/priority tokens onto doc primitives where they fit and defining new app-level tokens for the rest. + +**Status (task lifecycle):** + +| Token | Color | Source | Logic | +|---|---|---|---| +| `status-todo` | Pewter `#3F4651` | doc | Neutral, "not started yet" | +| `status-in-progress` | dusty violet `#5B4A8A` | accent | Active = brand moment per Hybrid | +| `status-done` | Moss `#4A5D3F` | doc Success | Affirmative completion | +| `status-cancelled` | Ash `#9C9A92` | doc | Faded, "let go" | +| `status-paused` | Warning `#8B6F1E` | doc | Stalled, needs attention — replaces the old warm gold treatment | + +**Priority (loudness scale):** + +| Token | Color | Source | Logic | +|---|---|---|---| +| `priority-low` | Info `#3D5A6E` | doc | Cool, FYI — quietest end of the spectrum | +| `priority-medium` | Warning `#8B6F1E` | doc | Golden, mid-attention | +| `priority-high` | Error `#C04A1F` | doc | Terracotta, urgent | +| `priority-none` | Vellum/Ash | doc | No signal | + +The priority row reads as a clean cool→warm gradient (slate blue → golden brown → terracotta), which matches the semantic loudness — coherence the current ad-hoc palette doesn't have. + +**Other functional tokens:** + +| Token | Color | Logic | +|---|---|---| +| `wikilink` | dusty violet | Editorial brand moment per Hybrid | +| `overdue` | Error `#C04A1F` | Same as priority-high — overdue IS a priority signal | +| `toast-success` | Moss | doc semantic | +| `toast-error` | Error | doc semantic | +| `toast-info` | Info | doc semantic | +| `tag-bg` / `tag-text` | accent at 15% / accent | Per doc pill recipe | + +Each token gets a `*-bg` companion at low alpha (matching the existing pattern in `theme.css`). + +**Removed:** the warm gold accent (`--color-accent-warm: #b8860b`). Its two jobs split: + +- Dates and timestamps (knowledge cards, event details, chat) → use `text-secondary` instead. Dates are metadata, not a brand surface; muted is the correct register. +- Paused project status → use the new `status-paused` (Warning `#8B6F1E`) row above. Same golden-brown family, semantically aligned. + +### Typography — adopt the doc's stack and scale + +Adopt the doc's type stack and scale verbatim, with one deferred verification (long-form line-height in practice). + +- **Body font: Inter.** Replaces Scribe's current system-stack body font. Doc-defined; no Scribe-specific divergence. +- **Type scale:** as in the doc table — Display 40 / H1 32 / H2 24 / H3 18 / Body 15 / Body small 13 / Label 12 / Code 13 / Tiny 11. +- **Two weights only:** 400 regular, 500 medium. No 600/700 (reads heavy in dark mode and against the muted palette). +- **Family rules:** Fraunces at 18px+ only (Display, H1, H2). H3 and below = Inter. Code = JetBrains Mono. +- **Line height:** 1.5 body, 1.3 headings, **1.7 for long-form reading surfaces** (notes, journal entries). +- **Sentence case for everything**, except the Tiny micro-label style which gets uppercase + 0.08em letter-spacing. + +Mechanical rollout — value swaps in `theme.css` plus loading Inter and JetBrains Mono from Google Fonts (Fraunces is already loaded). + +### Light mode — concrete palette + +Fills in the warm-parchment direction picked earlier. Treat these as starting values; tune in practice. + +| Token | Hex | Role | +|---|---|---| +| Page bg | `#F5F1E8` | Warm cream — the "paper" | +| Card bg | `#FBF8F0` | Near-white, slightly warm — raised surfaces | +| Inset bg (inputs, code) | `#EFEAE0` | Slightly darker than page, "inset" feeling | +| Text primary | `#14171A` | Deep ink — Obsidian inverted | +| Text secondary | `#5A5852` | Warm mid-grey | +| Text muted | `#9A9890` | Warm light grey for hints/metadata | +| Border default | `#D9D6CE` | Warm light pewter, hairline weight | + +**Code-block exception:** in light mode specifically, code blocks use a slight cool wash (e.g. `#EBEDF0`) instead of the warm inset bg, so syntax highlighting reads cleanly. This is the mitigation for the "warm bg fights colored content" downside. + +The accent (`#5B4A8A` dusty violet), Moss, Bronze, Oxblood, and the semantic color set are **identical across themes** — only the surface and text palettes flip. + +### Chat-bubble codification — keep the Illuminated Transcript pattern + +The existing chat-bubble pattern (informally called "Illuminated Transcript") gets written into the design system as a documented chat component. Other apps in the family that add a chat surface inherit the pattern; Scribe's existing implementation continues to work with only color shifts. + +**User bubble (whisper):** +- Background: transparent +- Border: 0.5px Pewter (was: indigo-tinted) +- Text color: secondary (Vellum dark / `#5A5852` light) +- Right-aligned, rounded except bottom-right (subtle "from-me" tail) + +**Assistant bubble (lit):** +- Background: card surface (Iron dark / `#FBF8F0` light) +- Border: none on top/right/bottom; **2px solid accent (dusty violet) on left edge only** +- Box-shadow: accent-tinted glow + standard depth shadow (formula: `0 4px 28px rgba(, 0.14), 0 2px 8px rgba(0,0,0,0.4)` in dark; lower alphas in light) +- Text color: primary (Parchment dark / Obsidian-inverted light) +- Left-aligned, rounded except bottom-left + +The 2px-accent left edge is the "illumination" — like an illuminated capital in a manuscript. The shadow is the lift. Together they make the assistant bubble read as the *primary* voice, while the user bubble is the *margin note*. + +**Inline tool-call cards (`ToolCallCard`)** rendered inside an assistant bubble do NOT get their own border (per the border philosophy — the bubble already contains them). They use a slight surface tint to differentiate. + +### Iconography — adopt Lucide, enforce a scale + +Scribe currently hand-inlines SVG paths in 16+ Vue files, with 5 different stroke weights and 8+ different sizes. The visual style is already outline + rounded caps + `currentColor` stroke (matches the doc's intent), but there's no shared source and no scale discipline. + +**Migration policy:** + +1. **Install `lucide-vue-next`** as the icon source. Replace hand-inlined SVGs with imported components. Single source of truth. +2. **Strict size scale: 16px and 24px only.** Today's mix of 12/13/14/15/17/18/20 collapses to those two. 16 for inline-with-text and small affordances; 24 for nav and primary actions. +3. **Stroke weight per the doc: 1.5 at 24px, 1 at 16px.** Lighter than the current default of 2 — reads more refined, matches the muted palette philosophy. Overrides Lucide's default. +4. **Outline by default; filled only for active/selected state.** Introduces a new affordance Scribe doesn't currently use — bookmark/pin/star icons can switch outline → filled to indicate active state. Reserve filled style strictly for this. +5. **No emoji in chrome.** Replace the 3 files' emoji usage in UI labels/buttons/badges/empty states with Lucide equivalents. Emoji remain fine in *user content* (note bodies, chat messages the user typed). + +Work cost: ~30-60 individual icon swaps across the 16 files. Mechanical; doesn't require redesign of any component. + +### Voice and tone — adopt principles, defer formal audit + +The doc's voice register applies to Scribe (understated mythic — plain for functional UI, flavored for empty/error/loading states). No formal sweep of every UI string yet. + +**Approach:** apply the voice opportunistically as components are touched in the polish pass — when redesigning a settings tab, an empty state, or an error toast, rewrite the copy at the same time using the doc's register and examples table as the guide. A standalone audit pass is deferred unless drift becomes visible. + +### Border philosophy — structural, not decorative + +The doc treats borders as *structural* (Pewter neutral hairlines that say "boundary"), not decorative (Scribe today uses indigo-tinted borders that say "branded edge"). That principle suggests removing borders in places where surface tint and spacing already communicate separation. + +**Borders to remove:** + +- List rows (NotesListView, TasksListView, conversation history) — surface contrast + spacing should separate rows; current border reads as "boxed-in" +- Inline `ToolCallCard` inside chat bubbles — the bubble is already a container; an extra border feels like double-wrapping +- Filter chips and search-bar pills with a background tint — background does the work +- Empty-state callouts with dashed/bordered "nothing here yet" boxes — tinted background reads cleaner + +**Borders to keep (genuinely structural):** + +- Standalone card containers (Notes viewer, Task viewer, the new daily prep card) +- Modal / dialog edges +- Code blocks (separates content type, not just space) +- Focus rings (accessibility) +- Major section dividers within a panel + +Border weight is not load-bearing for Scribe — happy to use the doc's 0.5px hairline default; the *placement* discipline matters more than the weight. + +## Open threads (next iterations) + +*All initial-iteration threads resolved. Next phase is the polish pass — applying the system to existing UI, component by component. New threads will accumulate here as we discover gaps in the polish pass.*