# 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. Foundation pass shipped 2026-04-27 in `7a9a8b7` (palette, fonts, light mode, action tokens, hardcoded indigo cleanup, warm-gold deprecation). Surface phase shipped 2026-04-27 across `93a3beb` → `3c1ec40` (Lucide migration, Hybrid-rule button reclassification per surface, long-form line-height, two-weights-only). The system is now applied end-to-end; this section will fold into the main body once the result has had time to settle in real use.* ## 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) ### Foundation pass — shipped 2026-04-27 (`7a9a8b7`) Mechanical token + font + light-mode rewrite of `frontend/src/assets/theme.css`, plus a sweep of hardcoded indigo and `--color-accent-warm` references across ~14 component files. Action tokens (`--color-action-primary` Moss, `--color-action-secondary` Bronze, `--color-action-destructive` Oxblood, `--color-action-ghost-border` Pewter) are defined but not yet applied — buttons still flow through `--color-primary` and read as dusty-violet gradients in the meantime, by design. Spec lives at `docs/superpowers/specs/2026-04-27-design-system-polish-foundation-design.md` (gitignored, local-only). ### Surface phase — shipped 2026-04-27 (`93a3beb` → `3c1ec40`) Bundled as Hybrid (option C from the brainstorm): Lucide cross-cutting first, then surface-by-surface for the judgment work. Spec lives at `docs/superpowers/specs/2026-04-27-design-system-polish-surface-design.md` (gitignored, local-only). Seven PRs landed on `dev`: | PR | Commit | Surface | Notes | |---|---|---|---| | 1 | `93a3beb` | Lucide cross-cutting | 60 hand-inlined SVGs across 15 files → `lucide-vue-next`. Every chrome icon at 16 or 24. Emoji-as-icons (`✕`, `✓`, `🎤`, `📎`, `↻`, `↑`, `×`, `☀`/`☾`) swept across the chrome. AppLogo wordmark and the GraphView D3 mount kept as the legitimate exceptions. | | 2 | `3d916d7` | Journal | Buttons audited; `↻` weather refresh → Lucide `RotateCcw`; assistant bubble line-height bumped; redundant `.journal-title` font-family dropped; dead `.news-section` CSS removed. | | 3 | `4192a64` | Chat | `.message-content` long-form 1.7 line-height on assistant bubbles; ToolCallCard outer border removed (bubble already contains it; error state moved to a left-edge accent); bulk-delete recolored to Oxblood with Trash2 icon; `.bulk-link` accent → muted text. | | 4 | `efb3534` | Knowledge cluster | `.prose` line-height bumped to 1.7 globally so all reading surfaces inherit. Save → Moss; Delete → Oxblood + Trash2; Edit / Advance → Moss; Convert / Share → Bronze. | | 5 | `ff498ce` | Project + Workspace | Project save panel → Moss; milestone confirm/cancel → Moss/Bronze; modal-btn-danger and per-row delete affordances → Oxblood; "Open Workspace" stays accent (project-surface brand moment). | | 6 | `541e2ed` | Settings | Densest button surface — every `.btn-save`, `.btn-primary`, `.btn-secondary`, `.btn-danger`, `.btn-danger-outline`, `.btn-toggle-open` reclassified per Hybrid; missing `.btn-danger` style block added (was unstyled before). | | 7 | `3c1ec40` | Edge surfaces | Calendar `New Event` → Moss; EventSlideOver Save/Cancel/Delete reclassified; HomeView hero CTA stays accent (brand moment); two-weights-only sweep across Header/Home/Calendar/Graph. | **Cross-cutting changes folded in as the work touched files:** - Long-form 1.7 line-height on `.prose` (PR 4) — applies to Note viewer, Task viewer, chat assistant bubbles, anywhere markdown renders into a reading surface. - Two-weights-only (400 + 500) — every `font-weight: 600` and `700` snapped to `500` across all surface PRs. - Hardcoded `--color-danger` in destructive button contexts → `--color-action-destructive` (Oxblood). `--color-danger` (Error terracotta) preserved for validation/error messages, per the doc's distinction between Error and Destructive. - Adjacent `×` / `✕` / unicode-arrow emoji swept opportunistically as files were touched (PRs 5, 7). ### Out of scope — deferred indefinitely Items deliberately not addressed in this round; revisit when a real need surfaces: - Lucide stroke-weight overrides (doc spec: 1.5 at 24, 1 at 16; current: Lucide default 2). Touched components if they read too heavy in practice. - Filled-as-active icon state — no current affordance uses it; introduce when bookmark/pin/star toggles are added. - Type-scale / spacing-scale CSS variables — components keep literal values. - Token rename to `--fs-*` namespace — Scribe is the only FabledSword app sharing this codebase. - FabledSword lockup placement — waiting on the actual heraldic mark to be drawn. - Standalone voice/tone audit across every UI string — opportunistic-only; full sweep deferred unless drift becomes visible. - A handful of editor utility buttons (`.btn-suggest-tags`, `.btn-link-all`, AI assist generate/proofread/accept/reject set, etc.) — currently ghost-styled and visually compliant; revisited only if they read off in practice. ### Open threads *New threads will accumulate here as gaps surface in real use.*