Themes.
A theme recolours Paperkites and can restyle its type. It never changes the layout, beyond a few layout words described below. You pick themes in :settings: one for light mode and one for dark. See Settings.
The built-in themes
| Theme | Kind | What it is |
|---|---|---|
| Paper | light | the default: warm paper, serif notes |
| Daylight | light | white page, cool greys, blue links |
| Fjord | light | cold, airy, frost accents |
| Studio | light | pure white page, neutral greys, sans notes and mono meta |
| Pine | dark | soft green-grey night, parchment ink; the default dark theme |
Making your own
Your themes live in ~/.kites/themes/, never in your notes folder. Any .css file there is a theme, and its name is the file name without .css.
- Save a file into
~/.kites/themes/under a new name, such asink.css. A built-in's name, such aspine.css, is taken: that file isn't listed. - Say which row it belongs in on its first line:
/* kites-theme: light */or/* kites-theme: dark */. Without it, Paperkites judges by yourgroundcolour. - Change what you want, and pick it in
:settings.
The folder is watched: a theme shows in :settings the moment it's saved. :theme reload reads the files again.
The easiest start is paper.css, the built-in look spelled out. You can delete any line you don't change: anything a theme leaves out keeps paper's value. A dark theme has to recolour every surface and every ink it puts text on, so a dark theme usually sets every colour.
What a theme file is
A theme uses CSS syntax, so your editor highlights it, but it isn't CSS. Paperkites reads it, checks every line, and turns it into colours and fonts. Nothing in it reaches the page as written.
/* kites-theme: light */
@format 1;
/* the palette: paper's colours and fonts, by name */
:root {
ground: #faf9f5;
ink: #1f1e1b;
accent-text: #94461a;
font-ui: 'Inter', system-ui, sans-serif;
}
/* named parts of the app, for fine-tuning */
.page .title { font-family: 'Iowan Old Style', Georgia, serif; font-weight: 700; }
.list .title { color: accent-text; }
.pill { color: ink; background: fill; }
A file has two levels. Most themes only need the first.
- The palette (
:root) holds colours and fonts by name, as paper.css lists them, plus the ground pattern and the layout words. Changing a colour there changes everything built on it. - Named parts fine-tune one place, when it should differ from the palette.
@format 1; is optional; a file without it is format 1.
Named parts
A named part is a name, not a CSS selector. .page .title names the page title; which element draws it is Paperkites' business. That's why the app can change without breaking your theme, and why a theme can't reach anything that isn't on this list.
| Part | Accepts | What it is |
|---|---|---|
.page .title | color, font-family, font-weight, font-style | the title of every page: a note, a person, a tag, search |
.note .body | color | the text of a note, and of the capture box |
.list .title | color, font-family, font-weight, font-style | a note's title in a list, search results and backlinks |
.list .preview | color, font-style, font-size | the lines of a note's text under its title in a list |
.gutter .date | color | the date in the gutter (today keeps the accent) |
.pill | color, background | the status pill: messages and the command line |
.formatbar | color, background | the format bar over a selection |
Layout words
Besides colours and fonts, a theme picks a few layout words in :root. Paper's value comes first. Leave one out to keep paper's.
| Word | Values | What it sets |
|---|---|---|
list-layout | ledger | stream | ledger: the date in the gutter, the note beside it. stream: no gutter, one card per note, the time on the right |
meta-case | upper | lower | dates, section labels and counts: small caps, or lower-case mono |
capture-submit | hint | key | button | the end of the capture box: a "⌘↩ save" hint, a ⌘↩ keycap, or a Save button |
placeholder-style | normal | italic | the capture box's placeholder |
chip-style | ui | plain | #tags and @people in the interface face, or in the face of the text around them |
titlebar | none | path | the window's top strip: nothing, or the path (~/notes) |
column-width | 560px–760px | the reading column; your own width setting still wins |
row-radius | 0px–16px | the corners of list rows and the capture box together |
ground-pattern | plain | dotted | dotted-edges | the page: plain, dots behind everything, or dots left and right of the column |
To try a ground pattern over every theme, run :theme ground plain, :theme ground dotted or :theme ground dotted-edges. It lasts until the app restarts; nothing is saved.
Values
| Where | Accepted |
|---|---|
a colour in :root | #rgb or #rrggbb; rgba() only for scrim |
a font in :root | a font stack: family names, ending in a generic family (serif, sans-serif, monospace, system-ui, ui-serif, ui-sans-serif, ui-monospace, cursive) |
color, background | #rgb, #rrggbb, or a palette colour's name such as accent-text, which follows the palette |
font-family | a font stack, or a palette font's name such as font-ui |
font-weight | normal, bold, 100–900 |
font-style | normal, italic |
font-size | whole px, 12px–24px |
Colour names like red, rgb(), var(), url(), selectors, @import and a second rule for the same part aren't accepted.
Contrast
Paperkites checks your palette so text stays readable:
- Text needs 4.5:1 against every surface it sits on. The caret and focus ring need 3:1.
- A part given a
colororbackgroundis checked against every surface it sits on. - The ground's dots (
dotonground) must be between 1.05:1 and 1.40:1: quiet enough not to compete with the text, visible enough to be there.
When a theme has a mistake
A theme file with a mistake isn't used. Paper stands in (Pine, for dark), and the status pill shows the first problem with its file and line:
theme: /Users/you/.kites/themes/ink.css:12: .page .title margin: takes color, font-family, font-weight, font-style
| Message | Fix |
|---|---|
not a primitive | only the named parts above exist, written exactly as shown |
takes color, ... | that part doesn't accept that property |
isn't a #rgb / #rrggbb colour | use hex, not red, rgb() or var() |
isn't a font stack ending in a generic family | end the list with serif, sans-serif, monospace, … |
ink-4 on ground is 3.10:1, needs 4.5:1 | that text would be hard to read; darken the text or lighten the surface |
Fix the file and save it, or run :theme reload.
What a theme can't change
- Sizes and spacing: the gutter, spacing, radii other than
row-radius, the caret, font sizes other than the list preview, and the dot grid's size. - Layout, beyond the layout words: there are no borders, there's one column, and there's no toolbar.
Your reading settings beat the theme. A body font chosen in :settings wins over the theme's font-body, and your column width wins over its column-width.
paper.css
Every colour, font and layout word a theme can set, and every named part, at paper's values. Copy it into ~/.kites/themes/, rename it, and change what you like. You can also download it.
@format 1;
/* ~/.kites/themes/paper.css
The palette: every token a theme can set, with paper's values. Colours are #rgb or #rrggbb;
scrim alone may be rgba(). Fonts are a font stack ending in a generic family. */
:root {
/* surfaces */
ground: #faf9f5; /* the page */
paper: #ffffff; /* floating surfaces: summon, peek card, picker */
tint-active: #f6f3ea; /* the active (raw markdown) block */
fill: #f4f2ec; /* code blocks, quiet panels */
fill-warm: #f6f1e9; /* selected row in a list or picker */
bar: #f2efe6; /* not drawn since the status pill; kept, tokens are never removed */
highlight: #f4e3cd; /* search match */
mention: #f2e9dd; /* unlinked mention of a note title */
sidebar: #ebe7dc; /* the floating sidebar */
sidebar-selected: #ddd7c9; /* selected sidebar row */
pill: #f0ece3; /* the status pill */
selection: #efd6c3; /* text selection */
switch-off: #d9d4c8; /* vim switch, off */
scrim: rgba(36, 34, 30, 0.26); /* behind summon */
/* ink */
ink: #1f1e1b; /* titles, primary UI */
ink-body: #26241f; /* note body prose */
ink-2: #56534d; /* secondary UI, inactive pane body */
ink-3: #67635b; /* de-emphasised prose, backlink context */
ink-4: #6a665e; /* SMALLEST INK THAT PASSES 4.5:1 on --k-ground */
muted: #9c9890; /* decorative only — never body or label text */
faint: #b4b0a6; /* markdown markers, list bullets, the # and / */
marker: #bab5a8; /* raw ** [[ ]] markers inside an active block */
/* accent */
accent: #c2622f; /* cursor, glyphs, dots, marks — non-text */
accent-text: #a3501d; /* any accent used AS TEXT (4.5:1 on ground) */
accent-soft: #e6cbb2; /* resting link underline */
mode-insert: #4f6b4a; /* INSERT badge */
person: #5f6a3a; /* a person: @mentions, the username on a person page */
formatbar: #1f1e1b; /* the format bar over a selection */
formatbar-ink: #f1eee6; /* ink on the format bar */
/* todos */
task-marker: #b0552a; /* [ ] [x] [<] [/] [!] */
task-marker-muted: #67635a; /* [-] cancelled, [>] moved */
task-done: #67635a; /* text of a done, cancelled or moved todo */
task-strike: #67635a; /* the line through a done todo */
task-label: #767167; /* trailing label and date chips */
task-hover: #efeae0; /* behind a marker under the pointer */
/* graph */
cluster-1: #c2622f;
cluster-2: #7d8a4f;
cluster-3: #5b7a8c;
cluster-4: #9c6b4f;
cluster-none: #cfcabf; /* orphan node */
edge: #e0dcd1; /* link inside a cluster */
edge-cross: #c4b5a2; /* link between clusters — deliberately darker */
/* ground */
dot: #e8e4da; /* the dot grid on the ground: 1.05 to 1.40:1 on ground, keep it quiet */
ground-pattern: dotted-edges; /* plain | dotted | dotted-edges */
/* type */
font-body: 'Source Serif 4', Georgia, serif;
font-ui: 'IBM Plex Sans', system-ui, sans-serif;
font-mono: 'IBM Plex Mono', ui-monospace, monospace;
/* layout: paper's word first; see THEMES.md › Layout */
list-layout: ledger; /* ledger | stream */
meta-case: upper; /* upper | lower */
capture-submit: hint; /* hint | key | button */
placeholder-style: normal; /* normal | italic */
chip-style: ui; /* ui | plain */
titlebar: none; /* none | path */
column-width: 620px; /* 560px to 760px */
/* row-radius: 0px to 16px, for list rows and the capture box together; paper's are 8px and 12px */
}
/* Primitives: named parts of the app, for when one place should differ from the palette.
A colour can name a token (ink, accent-text, ...) so it follows the palette, or be a #hex. */
/* the title of every page: a note, a person, a tag, search */
.page .title {
color: ink;
font-family: font-body;
font-weight: 600;
font-style: normal;
}
/* the text of a note, and of the capture box */
.note .body {
color: ink-body;
}
/* a note's title in a list, search results and backlinks */
.list .title {
color: ink;
font-family: font-body;
font-weight: 600;
font-style: normal;
}
/* the lines of a note's text under its title in a list */
.list .preview {
color: ink-3;
font-style: normal;
font-size: 16px;
}
/* the date in the gutter (today keeps the accent) */
.gutter .date {
color: ink-2;
}
/* the status pill: messages and the command line */
.pill {
color: ink-4;
background: pill;
}
/* the format bar over a selection: bold, italic, link, tag, mention, code */
.formatbar {
color: formatbar-ink;
background: formatbar;
}