Skip to main content

max / alloy

Follow the repainted akari pair through the skeleton and the audit `tools/wcag_audit.py` had been broken on every current theme file since the tonal steps moved into makeover: it read `content.secondary` and `content.muted` as authored keys, and no theme names them any more. It now ports `derive_tonal_steps`, OKLab mix and the WCAG floor scan included, so the tool audits what a consumer actually renders. makeover stays the source of truth and this is the port. TOKENS.md's contrast tables are regenerated from that tool rather than hand-edited, and carry two new sections: why the accent is a violet, and why ANSI slot 9 no longer resolves to it. In the helix skeleton the palette entry `lantern` named a hue that is now a violet, so it is `accent`. Three rules moved with it. `warning` and `diagnostic.warning` pointed at the accent, which was defensible while the accent was an orange and is not now that a warning would render lavender; they take `yellow`, joining the rest of the diagnostic row on ANSI names. `ember` was a mix of the accent and danger, which with a violet accent is a muddy plum rather than an ember; it is warning and danger now, which is both what the name says and a third heading tone distinct from the other two.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01EhbCuw3Z8VHWq6VNZ4XK2B
Author: Max Johnson <me@maxj.phd> · 2026-09-08 17:36 UTC
Signed with PGP, not checked
Commit: 8b9ec58548e18f26da93fe9135855cd0bf52ff82
Parent: e2a9bef
5 files changed, +193 insertions, -88 deletions
M docs/TOKENS.md +55 -17
@@ -88,43 +88,81 @@
88 88
89 89 ## Verified contrast: Akari Dawn
90 90
91 - Method: OKLCH-agnostic; reads hex, computes WCAG 2.1 relative luminance directly.
91 + Method: OKLCH-agnostic; reads hex, computes WCAG 2.1 relative luminance directly. Every number below comes out of `tools/wcag_audit.py`; regenerate rather than hand-edit.
92 92
93 93 **Text on surfaces:**
94 94
95 95 | Pair | vs sunken | vs page | vs raised | vs overlay |
96 96 |---|---:|---:|---:|---:|
97 - | `content.primary` | 10.31 | 13.25 | 14.40 | 15.03 |
98 - | `content.secondary` | 8.15 | 10.48 | 11.39 | 11.88 |
99 - | `content.muted` | 5.01 | 6.44 | 7.00 | 7.30 |
97 + | `content.primary` | 11.19 | 14.38 | 16.74 | 18.06 |
98 + | `content.secondary` | 8.96 | 11.51 | 13.39 | 14.45 |
99 + | `content.muted` | 3.72 | 4.78 | 5.56 | 6.00 |
100 100
101 - All twelve pairings clear AA-text (4.5); most clear AAA (7).
101 + `primary` and `secondary` are AAA on every tier. `muted` is AA-text everywhere but the sunken well, where it holds AA-UI, which is what a deliberately recessive tone is for.
102 102
103 103 **Borders on surfaces:**
104 104
105 105 | Pair | vs page | vs raised | vs overlay |
106 106 |---|---:|---:|---:|
107 - | `border-strong` (derived) | 3.27 | 3.55 | 3.71 |
108 - | `line.border` | 1.37 | 1.49 | 1.55 |
109 - | `border-subtle` (derived) | 1.12 | 1.22 | 1.27 |
107 + | `border-strong` (derived) | 6.34 | 7.38 | 7.96 |
108 + | `line.border` | 3.11 | 3.62 | 3.90 |
109 + | `border-subtle` (derived) | 1.37 | 1.59 | 1.72 |
110 110
111 - `border-strong` clears AA-UI on all three surfaces; the derivation formula works for Akari's soft border. `line.border` and `border-subtle` are decorative dividers, not required to meet 3.0.
111 + `line.border` now clears AA-UI on its own, so a control's edge is a boundary a reader can find rather than a hint the derivation has to rescue. `border-strong` is the emphatic tier above it and `border-subtle` stays decorative, not required to meet 3.0.
112 112
113 113 **Accents on surfaces:**
114 114
115 - | Accent | vs page | vs raised | vs sunken | vs overlay | Notes |
115 + | Accent | vs sunken | vs page | vs raised | vs overlay | Notes |
116 116 |---|---:|---:|---:|---:|---|
117 - | `action.primary` (lantern `#8a4530`) | 5.28 | 5.74 | **4.11** | 5.99 | AA-text on three of four; AA-UI on `sunken`, glyph-safe on the darkest tier |
118 - | `status.danger` (`#6a2828`) | 8.07 | 8.78 | 6.28 | 9.15 | AAA everywhere |
119 - | `status.success` (`#3a5830`) | 6.00 | 6.53 | 4.67 | 6.81 | AA-text everywhere |
120 - | `status.warning` (`#b07840`) | **2.80** | **3.05** | **2.18** | **3.18** | Fails AA-text on all tiers; AA-UI only on `raised`/`overlay`. **Amber-on-cream is inherent to Akari's aesthetic**; per the accent-on-glyph rule, warning is expressed as glyph + edge marker only. |
121 - | `status.info` (`#304050`) | 7.96 | 8.65 | 6.19 | 9.03 | AAA / AA-text everywhere |
117 + | `action.primary` (`#5a41a2`) | 4.68 | 6.02 | 7.00 | 7.56 | AA-text on all four |
118 + | `status.danger` (`#8f2420`) | 5.20 | 6.69 | 7.78 | 8.40 | AA-text or AAA everywhere |
119 + | `status.success` (`#2f5424`) | 5.26 | 6.76 | 7.87 | 8.49 | AA-text or AAA everywhere |
120 + | `status.warning` (`#875000`) | **4.00** | 5.14 | 5.98 | 6.45 | AA-text on three of four; AA-UI in the sunken well |
121 + | `status.info` (`#25415c`) | 6.39 | 8.20 | 9.55 | 10.30 | AAA / AA-text everywhere |
122 122
123 - Both failure modes are Akari-inherent rather than derivation bugs, and both survive Alloy's discipline: `action.primary` on `surface.sunken` still clears AA-UI (glyph-safe on the darkest recessed panel), and `status.warning`'s amber is a glyph-only accent.
123 + One tier misses AA-text, and it misses on the one surface a light theme cannot help: `surface.sunken` is a recessed cream, and an amber legible against it is no longer an amber. Warning keeps AA-UI there and stays a glyph-plus-edge accent in a well, per the accent-on-glyph rule.
124 124
125 125 ## Verified contrast: Akari Night
126 126
127 - Text on surfaces all AAA or AA-text. Borders derived at 7+ contrast (dark themes have more headroom because the border tone is against a light content.primary). Notable accent behavior: `status.danger` at `#d25046` lands at 3.3–4.1:1 across surfaces: AA-UI territory, glyph-safe under the same rule. Full audit reproducible via the script.
127 + **Text on surfaces:**
128 +
129 + | Pair | vs sunken | vs page | vs raised | vs overlay |
130 + |---|---:|---:|---:|---:|
131 + | `content.primary` | 16.68 | 14.29 | 11.90 | 10.15 |
132 + | `content.secondary` | 12.81 | 10.97 | 9.14 | 7.79 |
133 + | `content.muted` | 5.96 | 5.10 | 4.25 | 3.63 |
134 +
135 + **Borders on surfaces:**
136 +
137 + | Pair | vs page | vs raised | vs overlay |
138 + |---|---:|---:|---:|
139 + | `border-strong` (derived) | 10.77 | 8.97 | 7.65 |
140 + | `line.border` | 4.33 | 3.61 | 3.08 |
141 + | `border-subtle` (derived) | 2.33 | 1.94 | 1.65 |
142 +
143 + **Accents on surfaces:**
144 +
145 + | Accent | vs sunken | vs page | vs raised | vs overlay | Notes |
146 + |---|---:|---:|---:|---:|---|
147 + | `action.primary` (`#b9a3f2`) | 8.87 | 7.59 | 6.32 | 5.39 | AA-text or AAA everywhere |
148 + | `status.danger` (`#f78077`) | 7.69 | 6.58 | 5.48 | 4.68 | AA-text everywhere |
149 + | `status.success` (`#96c97e`) | 10.13 | 8.68 | 7.23 | 6.16 | AA-text or AAA everywhere |
150 + | `status.warning` (`#e5ac62`) | 9.63 | 8.25 | 6.87 | 5.86 | AA-text or AAA everywhere |
151 + | `status.info` (`#93aec6`) | 8.43 | 7.22 | 6.01 | 5.13 | AA-text or AAA everywhere |
152 +
153 + Nothing on the dark side falls below AA-text. The overlay column is the tight one, since a popover face is the lightest surface a dark theme has and every accent is read against it.
154 +
155 + ## Why the accent is a lavender
156 +
157 + `action.primary` is the one hue the whole system wears: the focus ring, the caret, the pressed button, the selected row, `category.one`, and the keyword class in every generated editor theme. Akari's own accent is a lantern orange, which put the accent in the same corner of the wheel as `status.warning` and `status.danger` — so the color meaning "this is where you are" and the color meaning "something is wrong" were neighbors, and telling them apart on a chip or a one-cell gutter marker came down to saturation.
158 +
159 + A violet accent has no semantic neighbor. Red stays available for danger and amber for warning, and the ring is unmistakably not either of them. The warm tones are still the theme's ground: `surface.*` is cream on the light side and a warm near-black on the dark, and the selection wash stays amber precisely so that a lavender caret sitting inside it does not disappear into its own hue.
160 +
161 + The consequence to know about: on a light theme a lavender legible as text has to be a deep violet (`#5a41a2`), not the pale tint the word "lavender" suggests. A pale lavender is available to a consumer as a *surface* tint via `mix(surface.page, action.primary, ...)`; it is not what the ink can be.
162 +
163 + ## Why bright red is no longer the accent
164 +
165 + ANSI slot 9 used to resolve to `action.primary`, on the reasoning that the accent was a warm orange-red and so was bright red. That held only while the accent happened to be warm; pointed at a violet it turns every `\e[91m` in the terminal purple. Slot 9 is now `status.danger`, the same relationship slots 10, 11 and 12 have with their normal-intensity counterparts. A program painting an error in bright red is naming red, not naming the theme's accent.
128 166
129 167 ## What's deferred
130 168
@@ -74,8 +74,66 @@
74 74 max(0, min(255, g)),
75 75 max(0, min(255, b)))
76 76
77 + # ---------------------------------------------------------------- oklab
78 +
79 + def _to_oklab(h):
80 + r, g, b = (_linearize(c) for c in hex_to_srgb(h))
81 + l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b
82 + m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b
83 + s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b
84 + l_, m_, s_ = (v ** (1 / 3) if v >= 0 else -((-v) ** (1 / 3)) for v in (l, m, s))
85 + return (0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_,
86 + 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_,
87 + 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_)
88 +
89 + def _from_oklab(lab):
90 + L, A, B = lab
91 + l_ = L + 0.3963377774 * A + 0.2158037573 * B
92 + m_ = L - 0.1055613458 * A - 0.0638541728 * B
93 + s_ = L - 0.0894841775 * A - 1.2914855480 * B
94 + l, m, s = l_ ** 3, m_ ** 3, s_ ** 3
95 + def _delin(c):
96 + c = 12.92 * c if c <= 0.0031308 else 1.055 * (max(c, 0.0) ** (1 / 2.4)) - 0.055
97 + return max(0, min(255, round(c * 255)))
98 + return "#{:02x}{:02x}{:02x}".format(
99 + _delin(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s),
100 + _delin(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s),
101 + _delin(-0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s))
102 +
103 + def oklab_mix(a_hex, b_hex, t):
104 + """Perceptual mix, the one makeover derives with. t=0 => a, t=1 => b."""
105 + x, y = _to_oklab(a_hex), _to_oklab(b_hex)
106 + return _from_oklab(tuple(x[i] + (y[i] - x[i]) * t for i in range(3)))
107 +
77 108 # ---------------------------------------------------------------- derivation
78 109
110 + # makeover's tonal-step constants (makeover `src/emphasis.rs`). The ratios are
111 + # a starting point: each step is pushed further toward the page until it clears
112 + # STEP_FLOOR against the ink, so a theme gets a step that can be seen rather
113 + # than a step of the agreed size.
114 + STEP_RATIO = {"secondary": 0.12, "muted": 0.42}
115 + STEP_FLOOR = 1.21
116 + PROBE = 0.005
117 +
118 + def tonal_steps(ink, page):
119 + """content.secondary and content.muted, as makeover derives them at load.
120 +
121 + They are not authored. A theme file names `content.primary` and nothing
122 + else in that family, so this reproduces `makeover::derive_tonal_steps`
123 + rather than reading keys that are no longer in the file. The two must agree;
124 + makeover is the source of truth and this is the port.
125 + """
126 + out, reached = {}, 0.0
127 + for key in ("secondary", "muted"):
128 + ratio = max(STEP_RATIO[key], reached)
129 + while True:
130 + color = oklab_mix(ink, page, min(max(ratio, 0.0), 1.0))
131 + if contrast(color, ink) >= STEP_FLOOR or ratio >= 1.0:
132 + break
133 + ratio += PROBE
134 + out[key], reached = color, ratio
135 + return out
136 +
79 137 def derive(theme):
80 138 """Compute Alloy's extended tokens from a makeover theme.
81 139
@@ -92,10 +150,12 @@
92 150 # text gets there on both crisp (dark border) and soft (Akari-tier)
93 151 # borders. border-subtle is decorative — 60% toward surface reads
94 152 # as "hint of a divider" without adding contrast.
95 - return {
153 + out = {
96 154 "border-subtle": mix_hex(border, surface, 0.60),
97 155 "border-strong": mix_hex(border, primary, 0.65),
98 156 }
157 + out.update(tonal_steps(primary, surface))
158 + return out
99 159
100 160 # ---------------------------------------------------------------- reporting
101 161
@@ -130,8 +190,9 @@
130 190 print("Text on surfaces (target >= 4.5 for text; muted target 3.0)")
131 191 for key in ("primary", "secondary", "muted"):
132 192 target = UI_TARGET if key == "muted" else TEXT_TARGET
193 + ink = text[key] if key == "primary" else derived[key]
133 194 for s_key in ("page", "raised", "sunken", "overlay"):
134 - r = contrast(text[key], surf[s_key])
195 + r = contrast(ink, surf[s_key])
135 196 _row(f"content.{key} on surface.{s_key}", r, target)
136 197
137 198 # Borders on surfaces
@@ -220,7 +220,7 @@
220 220 if let Some(inner) = value.strip_prefix('{').and_then(|v| v.strip_suffix('}')) {
221 221 // A rule that sets its own background is contrasted against *that*,
222 222 // not against the page — `ui.statusline.insert` puts the page color
223 - // on a lantern chip, which is correct and would fail a check
223 + // on an accent chip, which is correct and would fail a check
224 224 // against the page. Only rules that let the page show through are
225 225 // this test's business.
226 226 if inner.contains("bg") {
@@ -1,6 +1,7 @@
1 - # Author: Shu Kutsuzawa <cappyzawa@gmail.com>
2 - # License: MIT
3 - # @{meta.name} — inspired by Japanese alleys lit by round lanterns.
1 + # Descended from Akari by Shu Kutsuzawa <cappyzawa@gmail.com>, MIT.
2 + # https://github.com/cappyzawa/akari-theme
3 + # The values below are makeover's own and no longer Akari's; the ancestry is.
4 + # @{meta.name} — the warm ground of a lantern-lit alley, under a violet accent.
4 5 #
5 6 # Generated by skelgen from makeover's theme of the same name. Every tone
6 7 # below is derived; nothing here is a hex literal. Edit the theme, not this.
@@ -17,7 +18,7 @@
17 18 "ui.cursor.normal" = { fg = "cursor-text", bg = "cursor" }
18 19 "ui.cursor.primary" = { fg = "cursor-text", bg = "cursor" }
19 20 "ui.cursor.primary.normal" = { fg = "cursor-text", bg = "cursor" }
20 - "ui.cursor.match" = { fg = "lantern", bg = "sunken", modifiers = ["bold"] }
21 + "ui.cursor.match" = { fg = "accent", bg = "sunken", modifiers = ["bold"] }
21 22 "ui.cursor.insert" = { fg = "cursor-text", bg = "green" }
22 23 "ui.cursor.primary.insert" = { fg = "cursor-text", bg = "green" }
23 24 "ui.cursor.select" = { fg = "cursor-text", bg = "magenta" }
@@ -34,12 +35,12 @@
34 35 "ui.gutter" = { bg = "background" }
35 36 "ui.gutter.selected" = { bg = "cursorline" }
36 37 "ui.linenr" = { fg = "bright-black" }
37 - "ui.linenr.selected" = { fg = "lantern" }
38 + "ui.linenr.selected" = { fg = "accent" }
38 39
39 40 "ui.statusline" = { fg = "foreground", bg = "surface" }
40 41 "ui.statusline.inactive" = { fg = "comment", bg = "surface" }
41 42 "ui.statusline.normal" = { fg = "background", bg = "green", modifiers = ["bold"] }
42 - "ui.statusline.insert" = { fg = "background", bg = "lantern", modifiers = ["bold"] }
43 + "ui.statusline.insert" = { fg = "background", bg = "accent", modifiers = ["bold"] }
43 44 "ui.statusline.select" = { fg = "background", bg = "magenta", modifiers = ["bold"] }
44 45 "ui.statusline.separator" = { fg = "bright-black", bg = "surface" }
45 46
@@ -63,7 +64,7 @@
63 64 "ui.virtual.jump-label" = { fg = "bright-red", modifiers = ["bold"] }
64 65
65 66 "ui.debug.breakpoint" = { fg = "red" }
66 - "ui.debug.active" = { fg = "lantern", modifiers = ["bold"] }
67 + "ui.debug.active" = { fg = "accent", modifiers = ["bold"] }
67 68
68 69 "ui.highlight" = { bg = "match-bg" }
69 70 "ui.highlight.frameline" = { bg = "surface" }
@@ -74,22 +75,22 @@
74 75
75 76 "ui.picker.header" = { fg = "bright-blue", modifiers = ["bold"] }
76 77 "ui.picker.header.column" = { fg = "bright-blue", modifiers = ["bold"] }
77 - "ui.picker.header.column.active" = { fg = "lantern", modifiers = ["bold"] }
78 + "ui.picker.header.column.active" = { fg = "accent", modifiers = ["bold"] }
78 79
79 80 # Diagnostics
80 81 "error" = { fg = "red", modifiers = ["bold"] }
81 - "warning" = { fg = "lantern" }
82 + "warning" = { fg = "yellow" }
82 83 "info" = { fg = "blue" }
83 84 "hint" = { fg = "comment" }
84 85
85 86 "diagnostic.error" = { underline = { color = "red", style = "curl" } }
86 - "diagnostic.warning" = { underline = { color = "lantern", style = "curl" } }
87 + "diagnostic.warning" = { underline = { color = "yellow", style = "curl" } }
87 88 "diagnostic.info" = { underline = { color = "blue", style = "curl" } }
88 89 "diagnostic.hint" = { underline = { color = "comment", style = "curl" } }
89 90 "diagnostic.unnecessary" = { modifiers = ["dim"] }
90 91 "diagnostic.deprecated" = { modifiers = ["crossed_out"] }
91 92
92 - "tabstop" = { underline = { color = "lantern", style = "dashed" } }
93 + "tabstop" = { underline = { color = "accent", style = "dashed" } }
93 94
94 95 # Diff
95 96 "diff.plus" = "green"
@@ -102,16 +103,16 @@
102 103 "diff.delta.conflict" = { fg = "conflict", modifiers = ["bold"] }
103 104
104 105 # Markup
105 - "markup.heading" = { fg = "lantern", modifiers = ["bold"] }
106 + "markup.heading" = { fg = "accent", modifiers = ["bold"] }
106 107 "markup.heading.marker" = { fg = "comment" }
107 - "markup.heading.1" = { fg = "lantern", modifiers = ["bold"] }
108 + "markup.heading.1" = { fg = "accent", modifiers = ["bold"] }
108 109 "markup.heading.2" = { fg = "amber", modifiers = ["bold"] }
109 110 "markup.heading.3" = { fg = "ember", modifiers = ["bold"] }
110 111 "markup.heading.4" = { fg = "amber" }
111 112 "markup.heading.5" = { fg = "comment", modifiers = ["bold"] }
112 113 "markup.heading.6" = { fg = "blue" }
113 114 "markup.list" = { fg = "cyan" }
114 - "markup.list.numbered" = { fg = "lantern" }
115 + "markup.list.numbered" = { fg = "accent" }
115 116 "markup.list.unnumbered" = { fg = "cyan" }
116 117 "markup.list.checked" = { fg = "green" }
117 118 "markup.list.unchecked" = { fg = "comment" }
@@ -127,8 +128,8 @@
127 128 "markup.raw.block" = { fg = "bright-green" }
128 129 "markup.normal.completion" = "foreground"
129 130 "markup.normal.hover" = "foreground"
130 - "markup.heading.completion" = { fg = "lantern", modifiers = ["bold"] }
131 - "markup.heading.hover" = { fg = "lantern", modifiers = ["bold"] }
131 + "markup.heading.completion" = { fg = "accent", modifiers = ["bold"] }
132 + "markup.heading.hover" = { fg = "accent", modifiers = ["bold"] }
132 133 "markup.raw.inline.completion" = { fg = "bright-green" }
133 134 "markup.raw.inline.hover" = { fg = "bright-green" }
134 135
@@ -145,7 +146,7 @@
145 146 "constant" = { fg = "constant" }
146 147 "constant.builtin" = { fg = "constant" }
147 148 "constant.builtin.boolean" = { fg = "constant" }
148 - "constant.character" = { fg = "lantern" }
149 + "constant.character" = { fg = "accent" }
149 150 "constant.character.escape" = { fg = "escape" }
150 151 "constant.numeric" = { fg = "constant" }
151 152 "constant.numeric.integer" = { fg = "constant" }
@@ -180,19 +181,19 @@
180 181 "punctuation.delimiter" = "foreground"
181 182 "punctuation.special" = { fg = "amber" }
182 183
183 - "keyword" = { fg = "lantern" }
184 - "keyword.control" = { fg = "lantern" }
185 - "keyword.control.conditional" = { fg = "lantern" }
186 - "keyword.control.repeat" = { fg = "lantern" }
187 - "keyword.control.import" = { fg = "lantern" }
188 - "keyword.control.return" = { fg = "lantern" }
189 - "keyword.control.exception" = { fg = "lantern" }
190 - "keyword.operator" = { fg = "lantern" }
184 + "keyword" = { fg = "accent" }
185 + "keyword.control" = { fg = "accent" }
186 + "keyword.control.conditional" = { fg = "accent" }
187 + "keyword.control.repeat" = { fg = "accent" }
188 + "keyword.control.import" = { fg = "accent" }
189 + "keyword.control.return" = { fg = "accent" }
190 + "keyword.control.exception" = { fg = "accent" }
191 + "keyword.operator" = { fg = "accent" }
191 192 "keyword.directive" = { fg = "macro" }
192 - "keyword.function" = { fg = "lantern" }
193 - "keyword.storage" = { fg = "lantern" }
194 - "keyword.storage.type" = { fg = "lantern" }
195 - "keyword.storage.modifier" = { fg = "lantern" }
193 + "keyword.function" = { fg = "accent" }
194 + "keyword.storage" = { fg = "accent" }
195 + "keyword.storage.type" = { fg = "accent" }
196 + "keyword.storage.modifier" = { fg = "accent" }
196 197
197 198 "operator" = "foreground"
198 199
@@ -203,7 +204,7 @@
203 204 "function.macro" = { fg = "macro" }
204 205 "function.special" = { fg = "bright-magenta" }
205 206
206 - "tag" = { fg = "lantern" }
207 + "tag" = { fg = "accent" }
207 208 "tag.builtin" = { fg = "blue" }
208 209
209 210 "namespace" = { fg = "amber" }
@@ -220,8 +221,10 @@
220 221
221 222 cursor = "@{action.primary}"
222 223 cursor-text = "@{surface.page}"
223 - # The selection is the page carrying a wash of the theme's warm accent, which
224 - # is what makes a selected run read as lit rather than merely shaded.
224 + # The selection is the page carrying a wash of the theme's warm tone, which is
225 + # what makes a selected run read as lit rather than merely shaded. Warm on
226 + # purpose, and not the accent: the caret is the accent, and a selection tinted
227 + # the same hue as the thing sitting inside it hides the caret in its own wash.
225 228 selection-bg = "@{mix(surface.page, status.warning, 0.25)}"
226 229 selection-fg = "@{content.primary}"
227 230 # One step off the page: enough to find the caret's line, not enough to stripe
@@ -267,8 +270,8 @@
267 270
268 271 # Named roles. These are what the highlight rules above actually reference; the
269 272 # ANSI names are here for the handful of rules that speak in them.
270 - lantern = "@{action.primary}"
271 - ember = "@{mix(action.primary, status.danger, 0.5)}"
273 + accent = "@{action.primary}"
274 + ember = "@{mix(status.warning, status.danger, 0.5)}"
272 275 amber = "@{status.warning}"
273 276 constant = "@{category.six}"
274 277 # Comments want to recede, which is what `muted` is for. The hand-written
@@ -1,7 +1,8 @@
1 1 @{! theme = night }
2 - # Author: Shu Kutsuzawa <cappyzawa@gmail.com>
3 - # License: MIT
4 - # @{meta.name} — inspired by Japanese alleys lit by round lanterns.
2 + # Descended from Akari by Shu Kutsuzawa <cappyzawa@gmail.com>, MIT.
3 + # https://github.com/cappyzawa/akari-theme
4 + # The values below are makeover's own and no longer Akari's; the ancestry is.
5 + # @{meta.name} — the warm ground of a lantern-lit alley, under a violet accent.
5 6 #
6 7 # Generated by skelgen from makeover's theme of the same name. Every tone
7 8 # below is derived; nothing here is a hex literal. Edit the theme, not this.
@@ -18,7 +19,7 @@
18 19 "ui.cursor.normal" = { fg = "cursor-text", bg = "cursor" }
19 20 "ui.cursor.primary" = { fg = "cursor-text", bg = "cursor" }
20 21 "ui.cursor.primary.normal" = { fg = "cursor-text", bg = "cursor" }
21 - "ui.cursor.match" = { fg = "lantern", bg = "sunken", modifiers = ["bold"] }
22 + "ui.cursor.match" = { fg = "accent", bg = "sunken", modifiers = ["bold"] }
22 23 "ui.cursor.insert" = { fg = "cursor-text", bg = "green" }
23 24 "ui.cursor.primary.insert" = { fg = "cursor-text", bg = "green" }
24 25 "ui.cursor.select" = { fg = "cursor-text", bg = "magenta" }
@@ -35,12 +36,12 @@
35 36 "ui.gutter" = { bg = "background" }
36 37 "ui.gutter.selected" = { bg = "cursorline" }
37 38 "ui.linenr" = { fg = "bright-black" }
38 - "ui.linenr.selected" = { fg = "lantern" }
39 + "ui.linenr.selected" = { fg = "accent" }
39 40
40 41 "ui.statusline" = { fg = "foreground", bg = "surface" }
41 42 "ui.statusline.inactive" = { fg = "comment", bg = "surface" }
42 43 "ui.statusline.normal" = { fg = "background", bg = "green", modifiers = ["bold"] }
43 - "ui.statusline.insert" = { fg = "background", bg = "lantern", modifiers = ["bold"] }
44 + "ui.statusline.insert" = { fg = "background", bg = "accent", modifiers = ["bold"] }
44 45 "ui.statusline.select" = { fg = "background", bg = "magenta", modifiers = ["bold"] }
45 46 "ui.statusline.separator" = { fg = "bright-black", bg = "surface" }
46 47
@@ -64,7 +65,7 @@
64 65 "ui.virtual.jump-label" = { fg = "bright-red", modifiers = ["bold"] }
65 66
66 67 "ui.debug.breakpoint" = { fg = "red" }
67 - "ui.debug.active" = { fg = "lantern", modifiers = ["bold"] }
68 + "ui.debug.active" = { fg = "accent", modifiers = ["bold"] }
68 69
69 70 "ui.highlight" = { bg = "match-bg" }
70 71 "ui.highlight.frameline" = { bg = "surface" }
@@ -75,22 +76,22 @@
75 76
76 77 "ui.picker.header" = { fg = "bright-blue", modifiers = ["bold"] }
77 78 "ui.picker.header.column" = { fg = "bright-blue", modifiers = ["bold"] }
78 - "ui.picker.header.column.active" = { fg = "lantern", modifiers = ["bold"] }
79 + "ui.picker.header.column.active" = { fg = "accent", modifiers = ["bold"] }
79 80
80 81 # Diagnostics
81 82 "error" = { fg = "red", modifiers = ["bold"] }
82 - "warning" = { fg = "lantern" }
83 + "warning" = { fg = "yellow" }
83 84 "info" = { fg = "blue" }
84 85 "hint" = { fg = "comment" }
85 86
86 87 "diagnostic.error" = { underline = { color = "red", style = "curl" } }
87 - "diagnostic.warning" = { underline = { color = "lantern", style = "curl" } }
88 + "diagnostic.warning" = { underline = { color = "yellow", style = "curl" } }
88 89 "diagnostic.info" = { underline = { color = "blue", style = "curl" } }
89 90 "diagnostic.hint" = { underline = { color = "comment", style = "curl" } }
90 91 "diagnostic.unnecessary" = { modifiers = ["dim"] }
91 92 "diagnostic.deprecated" = { modifiers = ["crossed_out"] }
92 93
93 - "tabstop" = { underline = { color = "lantern", style = "dashed" } }
94 + "tabstop" = { underline = { color = "accent", style = "dashed" } }
94 95
95 96 # Diff
96 97 "diff.plus" = "green"
@@ -103,16 +104,16 @@
103 104 "diff.delta.conflict" = { fg = "conflict", modifiers = ["bold"] }
104 105
105 106 # Markup
106 - "markup.heading" = { fg = "lantern", modifiers = ["bold"] }
107 + "markup.heading" = { fg = "accent", modifiers = ["bold"] }
107 108 "markup.heading.marker" = { fg = "comment" }
108 - "markup.heading.1" = { fg = "lantern", modifiers = ["bold"] }
109 + "markup.heading.1" = { fg = "accent", modifiers = ["bold"] }
109 110 "markup.heading.2" = { fg = "amber", modifiers = ["bold"] }
110 111 "markup.heading.3" = { fg = "ember", modifiers = ["bold"] }
111 112 "markup.heading.4" = { fg = "amber" }
112 113 "markup.heading.5" = { fg = "comment", modifiers = ["bold"] }
113 114 "markup.heading.6" = { fg = "blue" }
114 115 "markup.list" = { fg = "cyan" }
115 - "markup.list.numbered" = { fg = "lantern" }
116 + "markup.list.numbered" = { fg = "accent" }
116 117 "markup.list.unnumbered" = { fg = "cyan" }
117 118 "markup.list.checked" = { fg = "green" }
118 119 "markup.list.unchecked" = { fg = "comment" }
@@ -128,8 +129,8 @@
128 129 "markup.raw.block" = { fg = "bright-green" }
129 130 "markup.normal.completion" = "foreground"
130 131 "markup.normal.hover" = "foreground"
131 - "markup.heading.completion" = { fg = "lantern", modifiers = ["bold"] }
132 - "markup.heading.hover" = { fg = "lantern", modifiers = ["bold"] }
132 + "markup.heading.completion" = { fg = "accent", modifiers = ["bold"] }
133 + "markup.heading.hover" = { fg = "accent", modifiers = ["bold"] }
133 134 "markup.raw.inline.completion" = { fg = "bright-green" }
134 135 "markup.raw.inline.hover" = { fg = "bright-green" }
135 136
@@ -146,7 +147,7 @@
146 147 "constant" = { fg = "constant" }
147 148 "constant.builtin" = { fg = "constant" }
148 149 "constant.builtin.boolean" = { fg = "constant" }
149 - "constant.character" = { fg = "lantern" }
150 + "constant.character" = { fg = "accent" }
150 151 "constant.character.escape" = { fg = "escape" }
151 152 "constant.numeric" = { fg = "constant" }
152 153 "constant.numeric.integer" = { fg = "constant" }
@@ -181,19 +182,19 @@
181 182 "punctuation.delimiter" = "foreground"
182 183 "punctuation.special" = { fg = "amber" }
183 184
184 - "keyword" = { fg = "lantern" }
185 - "keyword.control" = { fg = "lantern" }
186 - "keyword.control.conditional" = { fg = "lantern" }
187 - "keyword.control.repeat" = { fg = "lantern" }
188 - "keyword.control.import" = { fg = "lantern" }
189 - "keyword.control.return" = { fg = "lantern" }
190 - "keyword.control.exception" = { fg = "lantern" }
191 - "keyword.operator" = { fg = "lantern" }
185 + "keyword" = { fg = "accent" }
186 + "keyword.control" = { fg = "accent" }
187 + "keyword.control.conditional" = { fg = "accent" }
188 + "keyword.control.repeat" = { fg = "accent" }
189 + "keyword.control.import" = { fg = "accent" }
190 + "keyword.control.return" = { fg = "accent" }
191 + "keyword.control.exception" = { fg = "accent" }
192 + "keyword.operator" = { fg = "accent" }
192 193 "keyword.directive" = { fg = "macro" }
193 - "keyword.function" = { fg = "lantern" }
194 - "keyword.storage" = { fg = "lantern" }
195 - "keyword.storage.type" = { fg = "lantern" }
196 - "keyword.storage.modifier" = { fg = "lantern" }
194 + "keyword.function" = { fg = "accent" }
195 + "keyword.storage" = { fg = "accent" }
196 + "keyword.storage.type" = { fg = "accent" }
197 + "keyword.storage.modifier" = { fg = "accent" }
197 198
198 199 "operator" = "foreground"
199 200
@@ -204,7 +205,7 @@
204 205 "function.macro" = { fg = "macro" }
205 206 "function.special" = { fg = "bright-magenta" }
206 207
207 - "tag" = { fg = "lantern" }
208 + "tag" = { fg = "accent" }
208 209 "tag.builtin" = { fg = "blue" }
209 210
210 211 "namespace" = { fg = "amber" }
@@ -221,8 +222,10 @@
221 222
222 223 cursor = "@{action.primary}"
223 224 cursor-text = "@{surface.page}"
224 - # The selection is the page carrying a wash of the theme's warm accent, which
225 - # is what makes a selected run read as lit rather than merely shaded.
225 + # The selection is the page carrying a wash of the theme's warm tone, which is
226 + # what makes a selected run read as lit rather than merely shaded. Warm on
227 + # purpose, and not the accent: the caret is the accent, and a selection tinted
228 + # the same hue as the thing sitting inside it hides the caret in its own wash.
226 229 selection-bg = "@{mix(surface.page, status.warning, 0.25)}"
227 230 selection-fg = "@{content.primary}"
228 231 # One step off the page: enough to find the caret's line, not enough to stripe
@@ -268,8 +271,8 @@
268 271
269 272 # Named roles. These are what the highlight rules above actually reference; the
270 273 # ANSI names are here for the handful of rules that speak in them.
271 - lantern = "@{action.primary}"
272 - ember = "@{mix(action.primary, status.danger, 0.5)}"
274 + accent = "@{action.primary}"
275 + ember = "@{mix(status.warning, status.danger, 0.5)}"
273 276 amber = "@{status.warning}"
274 277 constant = "@{category.six}"
275 278 # Comments want to recede, which is what `muted` is for. The hand-written