Most iOS apps treat dark mode as an afterthought — invert some colours, call it done. Knotos was designed dark-first: deep navy backgrounds, indigo accents, and amber as the single warm highlight colour. Light mode adapts from there, not the other way around.
The colour palette
Two primary colours drive the entire system:
- Indigo #292E8C — primary action colour, bubble backgrounds, active states. Deep enough to feel premium, saturated enough to read clearly on dark backgrounds.
- Amber #FFB833 — online presence, unread badges, call accept, CTAs. The single warm note in a cool palette — it draws the eye exactly where it should.
Everything else is neutral: near-black backgrounds (#141729 and#1C1E2E), white with opacity for secondary text, andsystemGray6 for input fields.
BrandTheme — a single source of truth
Rather than scattering colour literals across views, Knotos centralises design tokens in a BrandTheme struct:
struct BrandTheme {
static let appName = "Knotos"
static let primary = Color(red: 0.161, green: 0.180, blue: 0.549) // indigo
static let accent = Color(red: 1.0, green: 0.722, blue: 0.200) // amber
static func adaptiveBackground(_ scheme: ColorScheme) -> Color {
scheme == .dark
? Color(red: 0.078, green: 0.082, blue: 0.114) // #141729
: Color(red: 0.973, green: 0.969, blue: 0.957) // cream
}
}Any design change — a brand refresh, an A/B test — happens in one file. Views never hardcode hex values.
The KnotLogo — pure SwiftUI
The logo is drawn in code, not loaded as an image asset. Two overlapping circles using ZStack, Circle(), andtrim() modifiers. This means it scales perfectly to any size, renders crisply on all display densities, and animates trivially.
Message bubbles and typography
Sent messages use a translucent amber background — Color.amber.opacity(0.15)with an amber border — rather than a solid fill. This keeps the bubbles light and readable without overwhelming the conversation. Received messages use solid indigo.
Font sizes follow a strict scale: 17pt for message body (matching iOS default), 13pt for metadata, 15pt for navigation labels. Every text style uses.system(size:weight:design:) with .rounded for headings and .default for body — no custom fonts to bundle.
Input fields
Fields use systemGray6 as the background — slightly lighter than the screen background — with a 1.5pt indigo stroke that appears only when the field is focused. This gives clear focus feedback without the aggressive coloured border that most apps use.
Adaptive vs. dark-only
Despite being dark-first, Knotos fully supports light mode. TheadaptiveBackground helper switches between near-black and cream. Accent colours stay the same in both modes — indigo and amber have enough contrast on both backgrounds to work without variants.
