diff options
| -rw-r--r-- | docs/design/theme-studio-perceptual-color-metrics-spec.org | 576 | ||||
| -rw-r--r-- | docs/design/theme-studio-seeding-engine-spec.org | 350 | ||||
| -rw-r--r-- | scripts/theme-studio/README.md | 11 | ||||
| -rw-r--r-- | scripts/theme-studio/colormath.js | 170 | ||||
| -rw-r--r-- | scripts/theme-studio/dupre-revised.json | 10411 | ||||
| -rw-r--r-- | scripts/theme-studio/dupre.json | 175 | ||||
| -rw-r--r-- | scripts/theme-studio/generate.py | 45 | ||||
| -rw-r--r-- | scripts/theme-studio/test-colormath.mjs | 149 | ||||
| -rw-r--r-- | scripts/theme-studio/theme-coloring-guide.org | 473 | ||||
| -rw-r--r-- | scripts/theme-studio/theme-studio.html | 201 | ||||
| -rw-r--r-- | todo.org | 50 |
11 files changed, 12587 insertions, 24 deletions
diff --git a/docs/design/theme-studio-perceptual-color-metrics-spec.org b/docs/design/theme-studio-perceptual-color-metrics-spec.org new file mode 100644 index 00000000..7e7dedb2 --- /dev/null +++ b/docs/design/theme-studio-perceptual-color-metrics-spec.org @@ -0,0 +1,576 @@ +#+TITLE: theme-studio — perceptual color metrics (OKLCH, APCA, ΔE) +#+AUTHOR: Craig Jennings +#+DATE: 2026-06-08 + +* Status + +Spec / review incorporated (Codex, 2026-06-08, two passes). Adds perceptual color metrics to +the theme-studio (=scripts/theme-studio/=) so it can build deliberately +low-contrast themes (Solarized / Zenburn class) with the same rigor it already +brings to high-contrast WCAG checking. Four additions: an OKLCH color model, a +per-color perceptual-lightness readout, an APCA contrast score alongside the +existing WCAG ratio, and a pairwise ΔE distinguishability check across the +palette. + +Came out of a design conversation comparing the low-contrast school (Solarized, +Zenburn) against Prot's high-contrast Modus themes. The conclusion: a theme has +three independent dials — contrast ratio, overall luminance, and chroma — and +the low-contrast camp turns down the first while Modus leaves it high and turns +down the other two. The current tool only measures the first (WCAG contrast) and +edits color in HSV, whose "lightness" is not perceptually uniform. To build +low-contrast themes by metric rather than by eye, the tool needs +perceptually-uniform lightness and chroma controls plus distinguishability and +polarity-aware contrast measures. + +Rubric: *Ready.* The four v1 product questions are decided in "Agreed decisions +(v1)" below and confirmed by Craig (2026-06-08); the testing strategy was +revised on his direction to a layered pyramid (Node-unit-tested color core + +thin UI hash tests + measured coverage). No remaining blocking ambiguity — the +implementer no longer has to invent product behavior while coding. Implementation +is sequenced into five phases, each independently shippable and tested. Tasks +filed in =todo.org=. + +* Background — the current color model + +The tool today works entirely in sRGB hex, HSV, and WCAG luminance. The relevant +cluster in =generate.py=: + +- =rl(hex)= (line 517) — WCAG relative luminance, via the existing =lin()= + sRGB-linearization helper. +- =contrast(a,b)= (line 519) — the WCAG 2.x ratio =(L1+0.05)/(L2+0.05)=. +- =rating(r)= / =ratingColor(r)= (lines 520-521) — AA (≥4.5) / AAA (≥7) verdict + and its display color. +- =hsv2rgb=, =rgb2hsv=, =hex2rgb=, =rgb2hex=, =normHex= (lines 604-609). +- The picker holds state as =pkH, pkS, pkV= (HSV) and renders an SV box (=#sv=), + a hue strip (=#hue=), crosshairs (=#svcur=, =#huecur=), a hex+contrast readout + (=#pkhex= / =#pkcon=, line 451), the contrast-mask buttons (=.pmode=, state + =pkMode=, values =any= / =aa= / =aaa=), and palette chips (=#pkchips=). +- =drawMask()= (line 613) greys SV-box regions whose contrast against the + background falls below the selected mask threshold (=pkThresh()=). +- Per-face contrast readouts appear across *three* tables — syntax (line 548), + UI (line 1064), and package faces (line 752) — each via =contrast()= + + =rating()=. The package-face tier has grown large since the tool's early + versions (51 packages in the current inventory), so any "add a column to the + table readouts" change now touches that whole surface, not just the two + original tables. + +Two limitations this spec addresses: + +1. *HSV lightness lies.* Two colors at the same HSV =V= can differ markedly in + perceived brightness, so the SV box cannot hold perceived lightness constant + while hue changes — exactly the operation a calm, even palette needs. +2. *WCAG 2.x is a known-flawed contrast model in the low-contrast / dark band.* + Its ratio misjudges contrast most where this work operates, and it is not + polarity-aware: it scores light-on-dark and dark-on-light identically, which + perception does not. WCAG 3 is reworking contrast but is years out — still a + Working Draft in 2026, with the final Recommendation not expected until + roughly 2028–2030 — and its contrast algorithm is undetermined: APCA was moved + *out* of the WCAG 3 draft in 2023 for further evaluation. So APCA enters here + as a well-regarded independent perceptual model used as an additional + diagnostic, not as a coming standard. WCAG 2.x stays the baseline precisely + because nothing has replaced it yet. + +* Goal + +Add four metrics, each a discrete increment: + +1. *OKLCH color model* — perceptually-uniform Lightness / Chroma / Hue, so the + editor can move one axis without disturbing the others, plus a gamut clamp + for OKLCH values outside sRGB. +2. *Perceptual-lightness readout* — show each color's OKLCH L (and C, H) in the + picker, so "low, even lightness steps" becomes a number rather than a guess. +3. *APCA score* — the Accessible Perceptual Contrast Algorithm Lc value + displayed next to the WCAG ratio, as the more trustworthy contrast metric in + the low-contrast band. +4. *Pairwise ΔE check* — perceptual color-difference between every pair of + palette entries, flagging pairs too similar to tell apart, which is the + constraint that keeps a low-chroma / low-lightness-spread palette from + collapsing into mush. + +Non-goals: replacing WCAG (it stays as the compatibility baseline, shown +alongside APCA, which is an additional perceptual diagnostic, not a +replacement); replacing the HSV picker outright (OKLCH is added as a parallel +color model, HSV remains the default); CIEDE2000 in v1 (ΔE-OK is the v1 +difference metric — see vNext). + +* Agreed decisions (v1) + +Settled on author + reviewer alignment and confirmed by Craig (2026-06-08). + +1. *ΔE metric and threshold.* Use ΔE-OK (Euclidean distance in OKLab) on its + native scale (OKLab L is 0..1). Default "too similar" warning threshold is + *0.02* — the just-noticeable-difference floor, so the warning fires only when + two palette colors are genuinely hard to tell apart. The threshold is a named + constant, calibratable in one place. CIEDE2000 (the CIE's 2000 perceptual + color-difference standard — more accurate than plain Euclidean distance, but + ~40 lines of trigonometric lightness/chroma/hue corrections plus a blue-region + rotation term) is deferred to vNext: ΔE-OK is accurate enough to flag + indistinguishable pairs, which is all this check needs, and it is five lines. +2. *Low-contrast preset.* v1 ships *readouts only* (OKLCH, APCA, ΔE). No named + low-contrast preset / mask mode yet. No such preset exists anywhere today — it + would be a new feature: a saved low-contrast target (e.g. an APCA Lc band, or + a contrast ceiling as well as a floor) that masks the palette to a comfortable + range in one click, the way the current any/AA+/AAA buttons mask by a contrast + floor. It is deferred until the raw readouts are in use, because only then is + it clear which band is worth presetting. v1 gives the numbers; the preset + would automate a judgment the numbers first have to inform. +3. *APCA placement.* v1 shows APCA *only in the picker* readout, not in the + syntax/UI/package table contrast cells. Adding it to the tables is + low-complexity once =apca()= exists — the same pattern as the existing + =contrast()= + =rating()= cells, repeated across the three tables — so the + deferral is about table *density*, not difficulty: the package table alone is + 51 packages wide, and a second contrast number per row risks clutter before + it is clear anyone reads it there. Table-wide APCA is a vNext candidate if + picker-only proves too hidden. +4. *Picker default model.* HSV stays the *default* picker model; OKLCH is + opt-in via a color-model control. The reason: HSV is the familiar 2D SV-box + the picker already has, and OKLCH is slider-only until the C×L plane (Phase + 4b) lands — so defaulting to OKLCH before 4b would hand users a worse default + editing surface than they have now. Once 4b ships the C×L plane, making OKLCH + the default becomes a real option worth revisiting; until then, HSV default + keeps the current editing experience intact and makes OKLCH an additive + choice, not a regression. + +* Color-math foundation (Phase 1, prerequisite) + +The pure color math is *extracted into its own importable module* rather than +inlined as loose functions in the page. This is the core architectural change +this spec makes to the test surface: the math is logic, so it gets tested as +logic — directly, in Node, with exhaustive fixtures — and the picker becomes a +thin UI layer over a tested core, not the only way to exercise the math. + +- New file: =scripts/theme-studio/colormath.js= — the pure, side-effect-free + conversion + metric functions, written as an ES module (each =export=-ed), + with a small guard so the same source loads both ways: =import=-ed by the Node + tests and spliced into the page by the generator. +- =generate.py= inlines =colormath.js= into the page's =<script>= the same way + it already inlines =samples.py='s data, so there is *one source of truth* — the + exact code the browser runs is the code the tests import. An inline-integrity + check (see Verification strategy) asserts the page contains the module verbatim + so the two can never drift. +- The existing inline helpers it supersedes (=lin=, =rl=, =contrast=, =rating=, + =hsv2rgb=, =rgb2hsv=, =hex2rgb=, =rgb2hex=) move into =colormath.js= too, so the + whole color core lives and is tested in one place. =normHex= stays at the UI + boundary; module functions assume a normalized =#rrggbb= and the Node tests + cover their edges directly. + +The functions (standard published algorithms): + +- =srgb2oklab(hex)= / =oklab2srgb(L,a,b)= — Björn Ottosson's OKLab matrices + (2020). sRGB → linear (reuse =lin()=) → LMS → cube-root → OKLab, and the + inverse. ~20 lines. +- =oklab2oklch(L,a,b)= / =oklch2oklab(L,C,H)= — Cartesian↔polar: =C=√(a²+b²)=, + =H=atan2(b,a)=. Trivial. +- =oklch2hex(L,C,H)= with the *gamut clamp* (see below). Returns + ={hex, clamped}= — the in-gamut hex plus a boolean flag. +- =apca(textHex, bgHex)= — the APCA-W3 algorithm. Returns a signed Lc (positive + for dark-text-on-light, negative for light-text-on-dark; magnitude ~0–107). +- =deltaE(aHex, bHex)= — ΔE-OK: Euclidean distance in OKLab, + =√((ΔL)²+(Δa)²+(Δb)²)=. Five lines. + +** Gamut clamp policy (v1, fixed) + +OKLCH can express colors sRGB cannot show (high C at some L/H). The v1 policy is +*binary-search chroma reduction*: hold L and H fixed, reduce C until the color +is in sRGB gamut. This preserves the two perceptual axes the user is reasoning +about and only sacrifices saturation. Component clipping (which can shift all +three axes and make a slider feel broken) is explicitly *not* used. + +=oklch2hex= returns ={hex, clamped}= where =clamped= is true when chroma was +reduced. The picker keeps its sliders and readouts on the *actual clamped color* +after conversion, and shows a short status ("chroma clamped to sRGB") when +=clamped= is true — so the user never sees an axis silently move. + +** APCA source (pinned) + +Implement against *APCA-W3 0.1.9* (Myndex), transcribing the constants verbatim: + +- Source: =https://github.com/Myndex/apca-w3= (the =apca-w3= package, version + 0.1.9). The implementation puts this URL + version in a code comment beside + =apca()=. +- Screen luminance per color uses the *exact* APCA-W3 0.1.9 =colorSpace= + constants, not rounded values: =Ys = 0.2126729·R^2.4 + 0.7151522·G^2.4 + + 0.0721750·B^2.4= on the 0..1 sRGB channels (straight 2.4 power, not the WCAG + piecewise). All remaining APCA constants — the black soft-clamp + (=blkThrs=/=blkClmp=), the polarity-specific text/background exponents + (=normBG=/=normTXT=/=revTXT=/=revBG=), the low-contrast roll-off + (=loBoThresh=/=loBoFactor=/=loClip=), =deltaYmin=, and =scaleBoW= — are + likewise transcribed verbatim from the pinned source. The spec does not restate + those numbers, to avoid becoming a second, drift-prone source: the pinned + =apca-w3= 0.1.9 is the single authority. +- Fixture values asserted by the Node unit tests: =apca('#000000','#ffffff')= + Lc ≈ *106.0* (dark on light, positive); =apca('#ffffff','#000000')= Lc ≈ + *-107.9* (light on dark, negative); plus at least one *chromatic* APCA fixture + (e.g. =apca('#67809c','#ffffff')=) computed from the pinned reference — + black/white alone cannot reveal rounded-coefficient drift, since the rounding + error is near zero at the channel extremes. + +The tool ships as a single self-contained generated HTML file with no runtime +build step or package manager, so the APCA algorithm is transcribed into +=colormath.js= (inlined into the page) rather than vendored as an npm dependency. +The Node test harness is dev-only — it imports =colormath.js= to assert against +fixtures — and does not make the shipped artifact depend on Node or any package. + +** Verification — Node unit tests (=test-colormath.mjs=) + +The math is tested *directly*, not through the browser: =scripts/theme-studio/test-colormath.mjs= +imports =colormath.js= and asserts against fixtures under =node --test=. No DOM, +no Chrome, sub-second, and not capped by what the UI happens to exercise — this +is where the bulk of the feature's test value lives, and it can be far more +exhaustive than a hash test. It must include *chromatic* fixtures and properties, +because many incorrect matrix/sign implementations still pass black, white, and +round-trip: + +- =srgb2oklab('#ffffff')= L ≈ 1.0, a ≈ 0, b ≈ 0; =srgb2oklab('#000000')= L ≈ 0. +- chromatic fixture 1 — saturated red =#ff0000=: OKLab/OKLCH within epsilon of + the reference (L ≈ 0.628, C ≈ 0.258, H ≈ 29.2°). +- chromatic fixture 2 — the dupre blue =#67809c=: OKLCH ≈ (L 0.591, C 0.052, + H 252°), epsilon ~0.005 on L/C and ~1° on H. Computed from the Ottosson + reference; the implementation verifies against the same reference it + transcribes. +- round-trip *property*: for a generated sample of hexes, + =oklch2hex(oklab2oklch(srgb2oklab(h))).hex= ≈ =h= within epsilon. A property + test over random inputs, not a fixed list — it explores corners a hand-written + list would miss. +- =apca= both polarities against the pinned fixtures above (assert sign and + magnitude), plus the chromatic APCA fixture. +- =deltaE(h,h)= = 0; =deltaE('#000000','#ffffff')= > 0; ordering: a near pair + scores below the 0.02 threshold, a well-separated pair above it. +- gamut clamp: a known out-of-gamut OKLCH (very high C) returns a valid + =#rrggbb= with L and H preserved within epsilon, C reduced, and =clamped= + true; an in-gamut input returns =clamped= false unchanged. + +Pure-function TDD with no rendering dependency: write the failing Node test, +confirm it FAILs (e.g. with a deliberately wrong constant), then make it pass. +There is no =#mathtest= browser hash — the math is not a UI concern, so it is not +tested through the UI. + +* Phase 2 — perceptual L and APCA readouts + +Smallest visible change; validates Phase 1 by eye. + +- Extend =pkReadout(hex)= (line 615) to populate new spans for OKLCH L / C / H + and APCA Lc, alongside the existing WCAG ratio in the =.pinfo= bar (line 451). + Add the spans to the picker DOM (lines 448-451) and minimal CSS. +- The APCA span carries a compact polarity-aware label (e.g. =APCA Lc -58=); the + sign convention (positive = dark-on-light, negative = light-on-dark) is + documented in its tooltip and in the README. +- WCAG remains exactly as-is in the picker and in all three table contrast cells. + Per "Agreed decisions" #3, no APCA in the tables for v1. + +Pure additions; no behavior changes. Headless guard: =#readouttest= loads a +known hex and asserts the OKLCH L/C/H and APCA Lc spans carry the expected +values and the WCAG readout is unchanged. + +* Phase 3 — pairwise ΔE across the palette + +Self-contained, high value for low-contrast work. + +- On =renderPalette()=, compute =deltaE= for every unordered pair of =PALETTE= + entries. Flag any pair below the threshold (0.02, the named constant). +- Warning copy and ordering: sort failing pairs ascending by ΔE (closest first), + show the first *5*, and append "and N more" when capped — so a noisy palette + never silently hides the count. Format: "blue / steel — ΔE 0.014, hard to + distinguish". +- Each palette chip's =title= gains its nearest-neighbor ΔE. +- Reuses the chip rendering already in =renderPalette= / =buildPkChips= (line + 619). No new rendering surface. + +Headless guard: =#deltatest= seeds two near-identical palette colors and asserts +the warning fires (and names the pair); seeds a well-spread palette and asserts +it does not; if the cap triggers, asserts the "and N more" suffix and ascending +order. + +* Phase 4 — the OKLCH editor + +The largest piece, and the one that delivers "hold lightness while changing +chroma." Two shippable sub-phases, in order. + +** Phase 4a — OKLCH sliders + color-model control + +- Add a *separate color-model control* — a segmented =HSV= / =OKLCH= toggle with + its *own* state variable =pkModel= — distinct from the existing contrast-mask + control (=.pmode= / =pkMode=, values =any= / =aa= / =aaa=). The two are + orthogonal concepts: =pkModel= is "how I edit the color," =pkMode= is "what + constraint I mask." They must not share state. +- In OKLCH mode, show L / C / H as numeric + range inputs that drive the color + through =oklch2hex=, updating =#newhexstr=, the swatch, and the readouts. On + clamp, the sliders snap to the clamped color and the status text appears. +- No canvas work; delivers the independent-dials benefit immediately. + +Headless guard: =#oklchtest= asserts that switching =pkModel= to OKLCH preserves +the selected color, that toggling the AA/AAA mask does *not* reset =pkModel=, and +that switching =pkModel= does *not* reset =pkMode=. + +** Phase 4b — Chroma×Lightness plane + +- When =pkModel= is OKLCH, render the SV box (=#sv=, line 448) as a Chroma (x) by + Lightness (y) plane at the current fixed hue; the hue strip is unchanged. The + crosshair maps to (C, L) instead of (S, V). +- *Gamut masking*: high chroma is unreachable at some L/H, so grey out the + out-of-gamut region of the plane — reuse the =drawMask()= pattern (line 613), + swapping the per-pixel test from "contrast < threshold" to "OKLCH(C,L,H) not + in sRGB gamut." The existing AA/AAA contrast mask can overlay on top. +- *Render cost*: =drawMask()= already samples at =step=4= and runs =contrast()= + per cell; the gamut test adds an OKLCH→sRGB conversion per cell, and a naive + per-cell binary search on top would be expensive while dragging. Bound it: use + a coarse sampling step, cache the rendered plane on a key of + (hue + dimensions + mask mode + background hex) so it only recomputes when one + changes, and defer the redraw until pointer movement settles. The background + hex is in the key because when the AA/AAA contrast overlay is active the mask + depends on =MAP['bg']=, so a background edit must invalidate the cached plane. + The in-gamut test per cell + needs only a forward conversion + channel-range check, not the full binary + search (that is reserved for committing a chosen color). +- This per-pixel gamut render is the only genuinely new rendering logic in the + spec, which is why it is sequenced last. + +Headless guard: open the picker in OKLCH mode on a known hex via a hash; assert +the C×L crosshair lands at the expected plane coordinates and that a known +out-of-gamut coordinate is masked. + +* Verification strategy (whole feature) + +The test surface is *layered* — a proper pyramid, broad and fast at the bottom, +thin and DOM-bound at the top: + +1. *Unit (Node, the core)* — =test-colormath.mjs= imports =colormath.js= and + asserts the math directly under =node --test=. No browser. This is the bulk of + the coverage and the place exhaustive testing lives (every conversion, both + APCA polarities + chromatic, gamut clamp, ΔE ordering, round-trip property + over random hexes). *Coverage is measured here* with Node's built-in reporter + (no extra dependency): =node --test --experimental-test-coverage scripts/theme-studio/=. + Target for =colormath.js= is ≥90% line/branch (testing.md's utility-code bar); + in practice a pure, fully-fixtured module should land at or near 100%, and a + gap points at an untested branch worth a case. Coverage of the *core* is a + gate; coverage of the browser-executed UI code is out of scope for v1 (it + needs CDP/c8 instrumentation and the UI is verified by assertion, not line + count). +2. *UI wiring (browser hash tests)* — only the things that genuinely need a DOM + or layout, now that the math is tested below them: =#cursortest= (crosshair + pixel position — needs real layout), =#readouttest= (Phase 2, spans populated), + =#deltatest= (Phase 3, warning list rendered), =#oklchtest= (Phase 4a, + =pkModel= / =pkMode= independence + color preserved across mode switch), the 4b + plane test (canvas render + gamut mask). Each appends a =PASS/FAIL= node; + command shape: + =google-chrome-stable --headless=new --dump-dom 'file://…/theme-studio.html#readouttest'=. +3. *Integration smoke* — =#selftest= (data roundtrip), re-run every phase to + confirm no regression. +4. *Inline-integrity* — a check (Node or grep) that the generated + =theme-studio.html= contains the =colormath.js= source verbatim, so the + tested module and the shipped inline copy cannot drift. + +Per-phase loop: edit the source (=colormath.js= for math, =generate.py= for the +page — never hand-edit =theme-studio.html=); =python3 generate.py= to regenerate; +=node --check= the emitted =<script>=; run the phase's tests (Node unit tests for +Phase 1, the matching hash test for UI phases); re-run =#selftest= and the +inline-integrity check; Chrome eyeball for the visible phases (2, 3, 4). + +On coverage and why this shape: =generate.py= (~1120 lines) and =samples.py= +(~269) are the templating/assembly + data layer — string-emission and a sample +corpus — so Python unit tests there are low value and stay out of scope. The +logic worth hammering is the color *math*, which is JavaScript; extracting it to +=colormath.js= makes it directly unit-testable in Node instead of only reachable +through the rendered app. That is the correction this revision makes: the earlier +draft tested the math through browser hash tests, which coupled math correctness +to the DOM and capped coverage at what the UI exercises. With the core extracted, +the math gets exhaustive direct unit tests and the browser tests shrink to UI +wiring — the thin-UI-over-tested-core shape an API-first build would have +produced. The separate =build-theme.el= converter keeps its 22 ERT tests. + +* Documentation + +Folded into the phases, landing with the code each describes: + +- README (=scripts/theme-studio/README.md=): document OKLCH, APCA, and ΔE; the + meaning of the signed APCA value; that WCAG remains the compatibility baseline + and APCA is an additional perceptual diagnostic, not a replacement. +- Add the exact commands beside the existing run instructions: the Node unit run + with coverage (=node --test --experimental-test-coverage scripts/theme-studio/=) + and the headless hash tests (=#readouttest=, =#deltatest=, =#oklchtest=, the 4b + plane test). + +* Acceptance criteria + +- *Phase 1*: =colormath.js= extracted and inlined by =generate.py=; + =node --test= green — achromatic, chromatic, and round-trip conversions within + epsilon; APCA matches the pinned fixtures (magnitude and sign, both polarities, + plus a chromatic fixture); gamut clamp preserves L/H within epsilon, reduces C, + returns =clamped= true on out-of-gamut and false unchanged on in-gamut; + inline-integrity check confirms the page contains =colormath.js= verbatim; + =node --test --experimental-test-coverage= reports =colormath.js= at ≥90% + line/branch. +- *Phase 2*: picker shows OKLCH L/C/H and APCA Lc (with polarity label) next to + the WCAG ratio; values match the Node-test references for hand-checked colors; + no behavior change to existing flows; tables unchanged; =#selftest= still PASS; + =#readouttest= PASS. +- *Phase 3*: a palette with two near-identical colors raises a visible warning + naming the pair and ΔE, sorted closest-first, capped at 5 with "and N more"; a + well-spread palette raises none; chip titles carry nearest-neighbor ΔE; + =#deltatest= PASS. +- *Phase 4a*: dragging L changes only lightness (C and H readouts hold); same for + C and H independently; =pkModel= and =pkMode= are independent (=#oklchtest= + PASS); clamp shows status text. +- *Phase 4b*: the C×L plane crosshair opens on the current color's (C, L); + out-of-gamut regions are masked; the plane render stays responsive while + dragging (cached on hue/dims/mask key). + +* Implementation phases + +One shippable phase per increment, in dependency order, each gated on its own +headless test plus a clean =#selftest=. These map to the drop-in =todo.org= +tasks (filed in workflow Phase 6, after Craig confirms Ready): + +1. *Math foundation* — extract the color core into =colormath.js= (OKLab/OKLCH, + APCA-W3 0.1.9, ΔE-OK, gamut clamp, plus the migrated lin/rl/contrast/hsv + helpers); =generate.py= inlines it; =test-colormath.mjs= unit tests + the + inline-integrity check; gate =node --test= green. +2. *Picker readouts* — OKLCH L/C/H + APCA Lc spans beside WCAG; gate + =#readouttest= + =#selftest=. +3. *Palette ΔE warnings* — pairwise ΔE, sorted/capped warning, chip-title + nearest-neighbor; gate =#deltatest=. +4a. *OKLCH sliders + color-model control* — =pkModel= separate from =pkMode=, + L/C/H inputs, clamp status; gate =#oklchtest=. +4b. *Chroma×Lightness plane* — gamut-masked C×L render with caching; gate the 4b + plane test. + +A test-surface task keeps the Node unit tests, the UI hash tests, the +inline-integrity check, =#selftest=, the script syntax check, and manual Chrome +validation green across the feature. + +* Review dispositions + +Modified or rejected recommendations only; everything else in the Codex review +(2026-06-08) was accepted as written and woven into the body above. + +- *Modified — APCA "transcribe vs vendor" question (high-priority finding 4).* + The review asked the spec to "state whether the project is comfortable + transcribing the algorithm rather than vendoring a package." Reframed as + settled rather than open: the tool is a single self-contained generated HTML + file with no build step or package manager, so transcription is the only path + consistent with the architecture. The source URL + version pin and the fixture + values were accepted in full. +- *Modified — ΔE-OK default threshold (high-priority finding 1 / open question).* + The review accepted ΔE-OK on its native scale "with a named default threshold" + but left the number to the author. Concretized to 0.02 (the OKLab + just-noticeable-difference floor) as a named, calibratable constant, so the + warning fires only on genuinely indistinguishable pairs rather than deferring + the choice to implementation. + +* Review and iteration history + +** 2026-06-08 Mon @ 13:00:34 -0500 — Codex — reviewer +- *What changed or was recommended:* Created the implementation-readiness review + and marked the spec =Not ready=. The review recommends resolving the listed + open questions, pinning the APCA source/fixtures, specifying OKLCH gamut clamp + semantics, separating color-model mode from contrast-mask mode, and converting + the increments into todo-ready implementation phases. +- *Why:* The feature direction fits the current theme-studio architecture, but + coding from this draft would force the implementer to decide product behavior + around DeltaE thresholds, APCA placement, OKLCH UI state, and out-of-gamut + colors. +- *Artifacts:* the review file (consumed and deleted on response). + +** 2026-06-08 Mon @ 13:08:00 -0500 — Claude Code — responder +- *What changed:* Processed every Codex recommendation. Accepted all five + high-priority findings — resolved the four open questions into "Agreed + decisions (v1)", fixed the gamut clamp as binary-search chroma reduction + returning a =clamped= flag with picker status text, separated =pkModel= + (HSV/OKLCH) from =pkMode= (mask), pinned APCA-W3 0.1.9 with black/white + fixtures, and added an "Implementation phases" decomposition (1, 2, 3, 4a, 4b) + with per-phase test gates. Accepted the medium findings: chromatic =#mathtest= + fixtures, ΔE warning sort/cap copy, C×L render-cost bounds, refreshed + background to include the package-face table surface, the named hash tests + (=#readouttest=, =#oklchtest=), and the README/doc additions. Two modifications + recorded in "Review dispositions": the APCA transcribe-vs-vendor question + (settled by the no-build architecture) and the ΔE-OK default threshold (set to + 0.02). +- *Why:* Converge to implementation-ready — remove every product decision from + the coding path. Rubric raised Draft → Ready pending Craig's confirm on the + four baked-in v1 decisions. +- *Artifacts:* consumed and deleted =theme-studio-perceptual-color-metrics-spec-review.org=; + see "Review dispositions" and "Agreed decisions (v1)". Implementation tasks to + be filed in =todo.org= on confirm (workflow Phase 6). + +** 2026-06-08 Mon @ 13:15:26 -0500 — Codex — reviewer +- *What changed or was recommended:* Re-reviewed the updated spec and marked it + =Not ready= on one remaining blocker: the APCA section pins =apca-w3= 0.1.9 and + says to transcribe constants verbatim, but still shows rounded luminance + coefficients instead of the exact published =colorSpace= constants. Also noted + two non-blocking edits: include background hex in the 4b mask cache key when + contrast masking is active, and either provide the =#67809c= OKLCH fixture + values or make that second chromatic fixture optional. +- *Why:* The implementation is otherwise ready-shaped, but APCA math and numeric + fixtures need a single authoritative source before coding starts. +- *Artifacts:* [[file:theme-studio-perceptual-color-metrics-spec-review.org][theme-studio-perceptual-color-metrics-spec-review.org]] + +** 2026-06-08 Mon @ 13:19:15 -0500 — Claude Code — responder +- *What changed:* Processed Codex's second pass. Accepted all three findings, no + modify/reject. Blocking: replaced the rounded APCA luminance coefficients + (=0.2126=/=0.7152=/=0.0722=) with the exact APCA-W3 0.1.9 =colorSpace= + constants (=0.2126729=/=0.7151522=/=0.0721750=), and stated the remaining APCA + constants are transcribed verbatim from the pinned source rather than restated + in the spec, so there is one authority. Non-blocking: added =MAP['bg']= to the + Phase 4b mask cache key (the AA/AAA overlay depends on background); added + concrete OKLCH fixture values for =#67809c= (L 0.591, C 0.052, H 252°); added a + chromatic APCA fixture to =#mathtest= so black/white can't hide coefficient + drift. +- *Why:* Remove the last numeric ambiguity so =#mathtest= fixtures and the + implementation agree on one exact APCA algorithm. Reviewer confirmed no design + gaps remain — only the author-confirm caveat. +- *Artifacts:* consumed and deleted the second + =theme-studio-perceptual-color-metrics-spec-review.org=. Rubric stays =Ready, + pending author confirm= on the four v1 decisions; Phase 6 task-filing still + holds for that confirm. + +** 2026-06-08 Mon @ 13:21:11 -0500 — Codex — reviewer +- *What changed or was recommended:* Re-read the spec-review workflow and + critically reviewed the updated spec against the current theme-studio code, + README, prior review dispositions, and task tracking. Assigned =Ready with + caveats=: no blocking implementation ambiguity remains, and the prior APCA + coefficient issue is resolved by the exact =apca-w3= =colorSpace= constants. + The only caveat is the spec's explicit author-confirm step before Phase 1. +- *Why:* The spec now defines v1 scope, APCA source/fixtures, OKLCH gamut policy, + picker state ownership, DeltaE threshold/copy, performance guardrails, docs, + acceptance criteria, and shippable phases well enough for implementation. +- *Artifacts:* No review file written; no blocking findings. + +** 2026-06-08 Mon @ 15:21:55 -0500 — Craig Jennings (review) + Claude Code (responder) — final review +- *What changed:* Craig's final-review questions (six cj comments) answered and + the load-bearing ones folded into the body. Factual correction: WCAG 3 is still + a Working Draft (final Recommendation ~2028–2030) and APCA was moved *out* of + the WCAG 3 draft in 2023 — so the Background no longer frames APCA as a coming + standard, only as an independent diagnostic, with WCAG 2.x kept as baseline + because nothing has replaced it. Clarifications added to the Agreed decisions: + what CIEDE2000 is and why ΔE-OK suffices (#1); that no low-contrast preset + exists today and what one would add (#2); that table APCA is low-complexity and + the deferral is about density not difficulty (#3); the reason HSV stays default + until the 4b plane lands (#4). The Verification section now states Python + coverage is ~0% by design (the generator is output-tested via hash tests) and + the target is per-behavior hash-test gating, not a line-coverage number. +- *Why:* Craig interrogated the decisions before confirming; the answers either + reinforce them or give him what he needs to override. No decision changed. +- *Artifacts:* WCAG 3 status via W3C/industry sources (June 2026); repo check + confirmed no Python test files / pytest config for =scripts/theme-studio/=. + +** 2026-06-08 Mon @ 15:34:36 -0500 — Craig Jennings (direction) + Claude Code (responder) — testing-strategy override +- *What changed:* Craig overrode the v1 testing approach. The prior draft tested + the color math through browser hash tests (=#mathtest=), which coupled math + correctness to the DOM and capped coverage at what the UI exercises. Corrected + to a layered pyramid: the pure math is extracted into =scripts/theme-studio/colormath.js= + (an importable ES module that =generate.py= inlines into the page), unit-tested + directly in Node (=test-colormath.mjs=, =node --test=) with exhaustive fixtures + + a round-trip property test; the browser hash tests shrink to UI wiring only + (=#cursortest=/=#readouttest=/=#deltatest=/=#oklchtest=/4b-plane); =#selftest= + stays as integration smoke; an inline-integrity check guards the module and the + inlined copy against drift. =#mathtest= is removed — the math is no longer a UI + concern. Updated Phase 1, Verification, Acceptance, Implementation phases, and + Documentation to match. Language correction: the math is JavaScript (emitted by + the Python), so the "Python unit tests" instinct lands as Node unit tests on the + extracted JS core; the Python stays templating/data and is out of test scope. +- *Why:* Test the core directly, keep the UI thin — the API-first shape this + app grew past. Direct unit tests on the math are faster, more exhaustive, and + not limited by the UI surface. +- *Decisions 1-4 confirmed* as written (4: OKLCH readouts always shown; only the + editing model is opt-in until 4b). Phase 6 task-filing + commit still pending + Craig's go. diff --git a/docs/design/theme-studio-seeding-engine-spec.org b/docs/design/theme-studio-seeding-engine-spec.org new file mode 100644 index 00000000..bcbf43db --- /dev/null +++ b/docs/design/theme-studio-seeding-engine-spec.org @@ -0,0 +1,350 @@ +#+TITLE: theme-studio — seeding engine (role table to guide-correct defaults) +#+AUTHOR: Craig Jennings +#+DATE: 2026-06-08 + +* Status + +Spec / review incorporated (Codex, 2026-06-08). Turns the color-assignment guide's seed table +and shade budget into an executable seeding engine: the tool opens with every +tier (syntax, UI faces, org-mode package faces) already colored to the guide's +defaults, so the user retunes hues with the picker rather than building a theme +from blank. Also reseeds the bundled =dupre= theme to the canonical compact +mapping (it currently diverges on two roles). + +Derives directly from =scripts/theme-studio/theme-coloring-guide.org= — the seed +table (role to palette-family / weight / channel) and the Shade budget (how many +shades each hue family carries). This spec encodes that table as data, classifies +each tier's faces into roles, and applies the table to produce the defaults. + +Rubric: *Ready.* Craig answered the four open questions (folded into Agreed +decisions) and Codex's review is incorporated. One decision reshapes the plan: v1 +generates shades with OKLCH (Craig's call), reusing the perceptual-metrics +=colormath.js= core, so this feature sequences after that spec's Phase 1. Two v1 +phases, each headless-testable. + +* Background — how the tool seeds today + +=scripts/theme-studio/generate.py= holds three face inventories, each with its +own ad-hoc default source: + +- *Syntax* — =CATS=, 21 categories keyed =bg p kw bi pp fnd fnc dec ty prop con + num str esc re doc cm cmd var op punc=. Defaults come from =COLS= (in + =samples.py=) into =MAP= and =BOLD=. There is no role layer; each category + carries a hand-set color. +- *UI faces* — =UI_FACES= (20 faces) with defaults in =UIMAP=, hand-authored. + This map already follows the guide closely (state faces are background-only, + active louder than idle, error/warning/success on the conventional hues), which + is the validation that the guide's principles describe a good UI tier rather + than invent one. +- *Package faces* — =APPS[app].faces=, each row =[face, label, default-dict]=. + =seedPkgmap()= reads the per-face default-dict. About twenty bespoke packages + (org, magit, elfeed, mu4e, ghostel, dashboard, lsp-mode, flycheck, dired, + dirvish, calibredb, erc, signel, pearl, slack, telega, shr, and more) carry + curated seed colors; generic inventory packages (from =package-inventory.json=) + seed to the default foreground. + +Three problems this spec addresses: + +1. *No role layer.* Each tier's defaults are set face-by-face by hand. There is + no single place that says "definitions are the warm anchor, bold" and projects + it onto syntax, UI, and org at once. The guide now states that table; the tool + does not consume it. +2. *dupre diverges from its own guide.* The compact mapping says builtins are + blue-grey and function definitions are gold; =dupre= assigns builtins to blue + (=bi= shares =kw='s hue) and definitions to silver (=fnd=). The guide records + this as a known divergence to be reseeded. +3. *Tiers do not open guide-correct.* UI is close by luck of hand-tuning; syntax + carries dupre's divergence; org's long tail is unseeded. Opening seeded across + all three is the goal. + +* Goal + +A seeding engine with three parts and one surfacing rule: + +1. *The seed model as data* — a named palette with the shade budget, a + role-to-treatment table, and a face-to-role map per tier. The guide's table, + made executable. +2. *A =seed()= operation* — applies the role table through each tier's + face-to-role map to produce the default assignments (=MAP=/=BOLD= for syntax, + =UIMAP= for UI, =PKGMAP= defaults for packages). +3. *Reseed dupre* — regenerate =dupre-revised.json= from the engine so it matches + the compact mapping (builtins blue-grey, definitions gold). + +Surfacing rule (Craig): the tool *opens seeded*. The syntax tier is already +guide-correct on load, so the user adjusts hues with the picker, then scrolls to +the UI faces. A "reseed from guide" button restores the defaults on demand. + +Non-goals: role-mapping the non-org bespoke packages (org is the one document +package worth a role map; the other ~20 keep their existing curated =APPS= seeds, +and reseed resets them to those defaults rather than flattening them — see +Package scope); per-tier reseed controls (v1 reseeds all three owned tiers at +once). + +* The seed model + +** Palette and shade budget + +A named swatch set, one to three shades per hue family, per the guide's Shade +budget. The names are the contract. v1 *generates* the shades with OKLCH (Craig's +call): each family is anchored by a base hue (the dupre anchors — blue, gold, +regal, sage, terracotta), and its quieter or brighter shades are derived by +stepping OKLCH lightness/chroma from that anchor, using the perceptual-metrics +=colormath.js= core. Generation is a first guess; any hue that reads wrong gets a +hand-authored override swatch. Rough shape: + +- *Neutrals:* =ground= (bg), =bg-dim=, =fg=, =muted-fg=, =comment=. +- *Blue:* =blue= (keyword), =blue-grey= (builtin — blue at lower chroma/lightness). +- *Gold:* =gold= (definition), =gold-quiet= (call). +- *Violet:* =regal= (types/decorators). +- *Green:* =sage= (string), =sage-muted= (docstring), =sage-bright= (escape). +- *Teal:* =teal= (regexp). +- *Terracotta:* =terracotta= (numbers/constants). +- *Signal:* =red=, =amber=, =green=, =blue= (reused) for error/warning/success/link. + +Roughly fifteen swatches across seven or eight hues. The builtin =blue-grey= and +the call =gold-quiet= are the swatches dupre is missing today and gains on +reseed. + +** Role-to-treatment table + +The guide's seed table as data: each role maps to a swatch, a weight, an optional +slant/underline, and a channel (foreground or background). One literal object, +e.g. + +#+begin_src js +ROLES = { + base: {swatch:'fg', weight:'normal', channel:'fg'}, + structure: {swatch:'muted-fg', weight:'normal', channel:'fg'}, + control: {swatch:'blue', weight:'bold', channel:'fg'}, + builtin: {swatch:'blue-grey', weight:'normal', channel:'fg'}, + def: {swatch:'gold', weight:'bold', channel:'fg'}, + call: {swatch:'gold-quiet', weight:'normal', channel:'fg'}, + type: {swatch:'regal', weight:'normal', channel:'fg'}, + string: {swatch:'sage', weight:'normal', channel:'fg'}, + docstring: {swatch:'sage-muted', slant:'italic', channel:'fg'}, + escape: {swatch:'sage-bright',weight:'normal', channel:'fg'}, + literal: {swatch:'terracotta', weight:'normal', channel:'fg'}, + comment: {swatch:'comment', slant:'italic', channel:'fg'}, + state: {swatch:'tint', channel:'bg'}, + sig_error: {swatch:'red', channel:'fg'}, + sig_warn: {swatch:'amber', channel:'fg'}, + sig_ok: {swatch:'green', channel:'fg'}, + sig_link: {swatch:'blue', underline:true, channel:'fg'}, + heading: {swatch:'ramp', channel:'fg'}, // see heading ramp +} +#+end_src + +** Face-to-role maps + +*** Syntax (CATS key to role) + +=p=, =var= to base; =op=, =punc=, =cmd= to structure; =kw= to control; =pp= to +control (shared, optionally muted); =bi= to builtin; =fnd= to def; =fnc= to call; +=dec=, =ty=, =prop= to type; =con=, =num= to literal; =str= to string; =doc= to +docstring; =esc=, =re= to escape (=re= to a teal variant if present); =cm= to +comment; =cmd= to structure (delimiter, dimmer). =bg= is the ground, set +directly. + +*** UI faces (UI_FACES to role) + +=region=, =hl-line=, =highlight=, =show-paren-match= to state (background tint, +no fg); =isearch= to an active match chip (may invert); =lazy-highlight= to a +quieter match; =isearch-fail=, =show-paren-mismatch= to sig_error; =error= to +sig_error, =warning= to sig_warn, =success= to sig_ok; =link= to sig_link; +=mode-line= to active chrome, =mode-line-inactive=, =line-number=, =fringe=, +=vertical-border= to idle/receding chrome; =line-number-current-line= to active +chrome; =cursor= to its own; =minibuffer-prompt= to control. + +*** Org-mode (face to one of six roles) + +=org-level-1..8= to heading ramp; =org-meta-line=, =org-drawer=, +=org-special-keyword=, =org-property-value=, =org-block-begin-line= / +=org-block-end-line=, =org-ellipsis=, =org-tag=, =org-date=, +=org-document-info-keyword= to markup-recede; =org-block=, =org-code=, +=org-verbatim=, =org-inline-src-block= to code-like (reuse the syntax literal +lane); =org-todo= / imminent deadlines to sig (warm), =org-upcoming-deadline= to +sig_warn, =org-scheduled= / =org-done= to receded/cool (with =org-done= taking +strikethrough); =org-link= to sig_link; =org-quote=, =org-verse= to emphasis +(italic). The org long tail that does not classify seeds to base, as today. + +** Package scope + +The role engine owns three default sources: syntax, UI, and the *org-mode* +package faces. It does not touch the other ~20 bespoke packages in =APPS= (magit, +elfeed, mu4e, and the rest): their curated seed colors stay exactly as today, and +the reseed button *resets them to their existing =APPS= defaults* rather than +role-generating or flattening them to foreground. Generic inventory packages keep +seeding empty/default. So =seed(model)= returns =packages.org-mode= only; the +non-org defaults continue to flow from =seedPkgmap()= over the curated =APPS= +dicts, and reseed re-runs =seedPkgmap()= for them. A =#seedtest= asserts a non-org +bespoke package (e.g. magit) keeps its curated seed after open and after reseed. + +Reseeding preserves the package-face import guarantees already established by +=mergePackagesInto= / =packagesForExport= (unknown app/face preservation, old-JSON +compatibility, recoverable references to deleted palette colors); this spec does +not re-decide them. + +** Heading ramp + +=org-level-1..8= share one hue across three or four lightness steps (the guide +does not spend eight distinct shades). v1 generates the steps with OKLCH: from a +base hue, step lightness down per level (level 1 strongest and bold, deeper levels +quieter), cycling the steps past level 4. This uses the same =colormath.js= shade +generation as the palette above. + +* The seed() operation + +A pure function, =seed(model)= returns ={syntax, ui, packages}= default +assignments: + +- *syntax*: for each =CATS= key, look up its role, resolve the role's swatch to a + hex and its weight, produce =MAP[key]= and =BOLD[key]=. +- *ui*: for each =UI_FACES= face, resolve its role to =UIMAP[face]= ({fg, bg, + bold, italic, underline}), honoring the channel (state roles set bg only). +- *packages.org-mode*: for each org face, resolve its role to a default-dict + ({fg, bg, bold, italic, strike, inherit, height}). + +The output is exactly the shape =exportObj()= already emits (=assignments=, +=ui=, =packages=), so =seed()= produces a =theme.json= the existing import path +loads unchanged. =packages= carries only =org-mode= (Package scope); the non-org +curated defaults flow through =seedPkgmap()= as today. Reseeding dupre is +=seed(model)= combined with the curated package seeds, written to +=dupre-revised.json= (the canonical package-aware artifact — see Surfacing). + +* Surfacing in the tool + +- *Open seeded.* The page's initial =MAP=/=UIMAP= come from =seed(model)= (inlined + defaults), not from hand-set =COLS=/=UIMAP=; =PKGMAP= comes from =seed(model)='s + org defaults plus =seedPkgmap()= over the curated =APPS= dicts for the rest. On + load the syntax tier is guide-correct; the user retunes hues and scrolls to UI. +- *Reseed button.* A "reseed from guide" control reapplies the seeds to all three + owned tiers and resets the non-org packages to their curated =APPS= defaults. It + warns first, naming the scope: "Reseed syntax, UI, and package defaults from the + guide? This discards current color assignments." +- *Canonical artifact.* The reseeded bundle is written to =dupre-revised.json=, + the full package-aware file the README and =build-theme.el= example use. + =dupre.json= stays a legacy minimal import fixture (no =packages= key) unless + deliberately migrated. Importing the reseeded =dupre-revised.json= and opening + fresh land on the same state. + +* Implementation phases + +1. *Seed model + seed() + tests.* Add the palette anchors + OKLCH shade + generation (reusing =colormath.js=), the =ROLES= table, and the three + face-to-role maps as data in =generate.py= (or a sibling inlined like + =samples.py=); write the pure =seed()=. Gate: =#seedtest= asserts representative + faces land on the right swatch/weight/channel in each tier (=bi= blue-grey, + =fnd= gold + bold, =var= base, =op= / =punc= muted, =doc= italic; =region= / + =hl-line= bg-only, =link= underlined, =error= / =warning= / =success= on signal + hues, active vs inactive chrome differentiated; =org-level-1= strongest, + =org-code= the fixed-pitch literal lane, =org-done= receded/struck) AND that a + non-org bespoke package (e.g. magit) keeps its curated seed. +2. *Open seeded + reseed + dupre-revised regen.* Wire the initial state to + =seed(model)= (plus =seedPkgmap()= for the non-org packages); add the all-tier + reseed button with the scope-named overwrite warning, resetting non-org + packages to their =APPS= defaults; regenerate =dupre-revised.json= from the + engine. Gate: =#selftest= still PASS; a headless check that default-on-open + equals =seed(model)=; an *artifact round-trip* check that the regenerated + =dupre-revised.json= imports back to the same seeded state (package defaults and + source markers included); a Chrome eyeball that the seeded syntax tier reads as + a coherent dupre. + +Dependency: v1 reuses the perceptual-metrics =colormath.js= core for OKLCH shade +generation, so it sequences after that spec's Phase 1 (the math foundation). No +second color-math implementation. + +* vNext candidates + +- Per-tier reseed controls (reseed just syntax, just UI, just org) after the + all-at-once v1 button. +- Role-mapping selected non-org bespoke packages beyond org, if their curated + defaults prove worth regenerating from the table. +- The guide-support views and advisories already tracked in =todo.org=. + +* Acceptance criteria + +- *Phase 1*: =seed()= is pure and table-driven; representative faces in all three + tiers resolve to the guide's seed-table treatment; a non-org bespoke package + keeps its curated seed; OKLCH generation produces the family shades and the + heading ramp; =#seedtest= PASS. +- *Phase 2*: the tool opens with syntax/UI/org seeded from =seed(model)= and the + non-org packages on their curated =APPS= defaults; the reseed button restores + all three owned tiers (and resets non-org to curated defaults) behind a + scope-named warning; =dupre-revised.json= is regenerated, matches the compact + mapping (=bi= blue-grey, =fnd= gold), and round-trips back to =seed(model)= on + import; =#selftest= PASS; a Chrome eyeball confirms a coherent dupre. + +* Agreed decisions (v1) + +Answered by Craig (2026-06-08), folded in. + +1. *Palette swatch source.* Generate the shades with OKLCH and fix hues that read + wrong by hand override (Craig overrode the hand-authored recommendation). This + moves OKLCH generation into v1 and makes the feature reuse the + perceptual-metrics =colormath.js= core, sequencing after that spec's Phase 1. +2. *Heading ramp depth.* Three or four distinct lightness steps, cycled across + levels 1-8. +3. *Converter sharing.* Tool-only for v1; =build-theme.el= consumes the exported + =theme.json= regardless. +4. *Reseed scope.* All three owned tiers at once; per-tier reseed is vNext. + +* Review dispositions + +Codex's review (2026-06-08) was accepted in full. The items below note the two +findings that corrected factual errors in the draft and the one open choice this +response resolved; everything else was woven into the body as written. + +- *Corrected — package scope (high-priority finding 2).* The draft said non-org + packages "seed to the default foreground." Wrong: =APPS= carries curated seeds + for ~20 bespoke packages. Rewritten so the role engine owns only org among + packages and the rest keep their curated =APPS= defaults, with reseed resetting + to those (see Package scope). +- *Corrected — canonical artifact (high-priority finding 3).* The draft named + =dupre.json=; the package-aware bundle is =dupre-revised.json=. Replaced + throughout, with =dupre.json= noted as the legacy minimal fixture. +- *Resolved — OKLCH dependency (high-priority finding 1).* The review offered two + routes to OKLCH-in-v1 (depend on the perceptual-metrics core, or build a local + minimal helper). Chose the dependency, to avoid a second color-math + implementation. + +* Sources + +- =scripts/theme-studio/theme-coloring-guide.org= — the seed table and Shade + budget this engine executes. +- =scripts/theme-studio/generate.py= — =CATS=, =UI_FACES=/=UIMAP=, =APPS= / + =seedPkgmap=, =exportObj= (the target shape). +- =docs/design/theme-studio-perceptual-color-metrics-spec.org= — the + =colormath.js= core that v1 OKLCH shade generation uses. + +* Review and iteration history + +** 2026-06-08 Mon @ 19:00:17 -0500 — Codex — reviewer +- *What changed or was recommended:* Created the implementation-readiness review + and marked the spec =Not ready=. The review treats the inline =cj: comment= + blocks as answered product input, then flags three remaining implementation + blockers: the palette-source answer moves OKLCH generation into v1 while the + phase plan still says vNext; the package seeding scope conflicts with the + current many-bespoke-app =APPS= surface; and the spec names =dupre.json= even + though the current README/build path uses =dupre-revised.json= as the full + package-aware artifact. +- *Why:* The role-table direction is sound, but those conflicts would force the + implementer to decide dependency order, package-default preservation, and + which bundled JSON file to write. +- *Artifacts:* the review file (consumed and deleted on response; see Review dispositions). + +** 2026-06-08 Mon @ 19:06:06 -0500 — Claude Code — responder +- *What changed:* Folded Craig's four answers into Agreed decisions and accepted every Codex finding. OKLCH shade generation moved into v1 (reusing =colormath.js=, sequenced after perceptual-metrics Phase 1); package scope rewritten so the engine owns only org and the ~20 non-org bespoke packages keep their curated =APPS= seeds (reseed resets to those); =dupre.json= references replaced with =dupre-revised.json= (canonical, package-aware) and =dupre.json= noted legacy; phases collapsed to two v1 phases with a vNext section; added the non-org-preserved and artifact-round-trip tests, the scope-named reseed warning, and the import-guarantee citation. +- *Why:* The draft described an older, narrower package surface and the wrong dupre artifact; left uncorrected, an implementer could wipe curated package defaults or write the wrong file. Two of the three blockers fixed errors in my draft. Rubric Draft to Ready. +- *Artifacts:* consumed and deleted the review file; see Review dispositions and Agreed decisions. + +** 2026-06-08 Mon @ 19:11:06 -0500 — Codex — reviewer +- *What changed or was recommended:* Re-reviewed the incorporated spec against + the current generator, README, task tracking, and previous findings. Assigned + =Ready=: the OKLCH dependency, non-org package seed preservation, and + =dupre-revised.json= artifact story are now explicit. Fixed one stale + non-blocking source note that still referred to Phase 3. +- *Why:* The spec now gives an implementer a coherent v1: two phases, explicit + dependency on perceptual-metrics Phase 1, table-driven =seed()=, open-seeded + and reseed behavior, package preservation rules, artifact round-trip tests, + and vNext boundaries. +- *Artifacts:* No review file written; no blocking findings. diff --git a/scripts/theme-studio/README.md b/scripts/theme-studio/README.md index 62034039..58ddbf81 100644 --- a/scripts/theme-studio/README.md +++ b/scripts/theme-studio/README.md @@ -8,6 +8,10 @@ Reassign colors against the palette, judge legibility with live WCAG-contrast readouts, then export a `theme.json` that a build step turns into `themes/<name>-*.el`. +For the color-assignment philosophy behind the tool — how to group syntax roles, +what to share, where to spend chroma and bold — see +[`theme-coloring-guide.org`](theme-coloring-guide.org). + ## Run ```bash @@ -47,6 +51,13 @@ Three tiers of faces, plus the palette: (saturation/value square, hue slider, palette reuse chips, live contrast readout, and an any / AA+ / AAA legibility mask). Remove, rename, reorder with arrows or drag. The colors serving as background and foreground are locked. + + The picker also shows perceptual readouts beside the WCAG ratio: the OKLCH + coordinates (lightness, chroma, hue°) and the APCA Lc contrast against the + ground color. APCA Lc is signed — positive means dark text on a light + background, negative means light text on a dark background — so a light color + on dupre's dark ground reads as a negative Lc. WCAG stays the rating used in + the syntax/UI/package tables; APCA and OKLCH are picker-only diagnostics. - **Syntax** — every font-lock / tree-sitter category (keyword, string, function, type, comment, and the rest), each with normal/bold/italic and a contrast rating. Click a category to flash its tokens in the code; click a diff --git a/scripts/theme-studio/colormath.js b/scripts/theme-studio/colormath.js new file mode 100644 index 00000000..367b6abe --- /dev/null +++ b/scripts/theme-studio/colormath.js @@ -0,0 +1,170 @@ +// colormath.js — pure color-math core for theme-studio. +// +// One source of truth: node imports this module (tests); generate.py inlines its +// body into the page (stripping the trailing export block) so the browser runs +// the same code. No DOM, no side effects. +// +// Algorithms: OKLab/OKLCH from Bjorn Ottosson (2020, +// https://bottosson.github.io/posts/oklab/); APCA from APCA-W3 0.1.9 +// (https://github.com/Myndex/apca-w3); deltaE is OKLab Euclidean distance. + +function hex2rgb(h) { + return [parseInt(h.substr(1, 2), 16), parseInt(h.substr(3, 2), 16), parseInt(h.substr(5, 2), 16)]; +} + +// sRGB transfer (0..1 channel <-> linear-light). +function lin(c) { return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); } +function delin(c) { return c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055; } +function clamp01(c) { return c < 0 ? 0 : c > 1 ? 1 : c; } + +function srgb2oklab(hex) { + const [R, G, B] = hex2rgb(hex); + const r = lin(R / 255), g = lin(G / 255), b = lin(B / 255); + const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b; + const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b; + const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b; + const l_ = Math.cbrt(l), m_ = Math.cbrt(m), s_ = Math.cbrt(s); + return { + L: 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_, + a: 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_, + b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_, + }; +} + +function oklab2oklch(lab) { + let H = Math.atan2(lab.b, lab.a) * 180 / Math.PI; + if (H < 0) H += 360; + return { L: lab.L, C: Math.hypot(lab.a, lab.b), H }; +} + +function oklch2oklab(L, C, H) { + const hr = H * Math.PI / 180; + return { L, a: C * Math.cos(hr), b: C * Math.sin(hr) }; +} + +// OKLab -> linear sRGB (may fall outside [0,1] when out of gamut). +function oklab2lrgb(L, a, b) { + const l_ = L + 0.3963377774 * a + 0.2158037573 * b; + const m_ = L - 0.1055613458 * a - 0.0638541728 * b; + const s_ = L - 0.0894841775 * a - 1.2914855480 * b; + const l = l_ * l_ * l_, m = m_ * m_ * m_, s = s_ * s_ * s_; + return [ + 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s, + -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s, + -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s, + ]; +} + +function inGamut(lrgb) { + const e = 1e-4; + return lrgb.every(c => c >= -e && c <= 1 + e); +} + +function lrgb2hex(lrgb) { + return '#' + lrgb.map(c => { + const v = Math.round(clamp01(delin(clamp01(c))) * 255); + return v.toString(16).padStart(2, '0'); + }).join(''); +} + +// OKLCH -> in-gamut sRGB hex. When the requested chroma is unreachable, reduce C +// by binary search holding L and H fixed; report whether clamping happened. +function oklch2hex(L, C, H) { + const lab0 = oklch2oklab(L, C, H); + const lrgb0 = oklab2lrgb(lab0.L, lab0.a, lab0.b); + if (inGamut(lrgb0)) return { hex: lrgb2hex(lrgb0), clamped: false }; + let lo = 0, hi = C; + for (let i = 0; i < 24; i++) { + const mid = (lo + hi) / 2; + const lab = oklch2oklab(L, mid, H); + if (inGamut(oklab2lrgb(lab.L, lab.a, lab.b))) lo = mid; else hi = mid; + } + const lab = oklch2oklab(L, lo, H); + return { hex: lrgb2hex(oklab2lrgb(lab.L, lab.a, lab.b)), clamped: true }; +} + +// APCA-W3 0.1.9. Returns signed Lc: positive for dark-text-on-light, negative +// for light-text-on-dark. Constants transcribed verbatim from the pinned source. +function apcaY(hex) { + const [R, G, B] = hex2rgb(hex); + return 0.2126729 * Math.pow(R / 255, 2.4) + + 0.7151522 * Math.pow(G / 255, 2.4) + + 0.0721750 * Math.pow(B / 255, 2.4); +} + +function apca(textHex, bgHex) { + const blkThrs = 0.022, blkClmp = 1.414, deltaYmin = 0.0005; + const normBG = 0.56, normTXT = 0.57, revTXT = 0.62, revBG = 0.65; + const scaleBoW = 1.14, scaleWoB = 1.14, loBoWoffset = 0.027, loWoBoffset = 0.027, loClip = 0.1; + let Ytxt = apcaY(textHex), Ybg = apcaY(bgHex); + Ytxt = Ytxt > blkThrs ? Ytxt : Ytxt + Math.pow(blkThrs - Ytxt, blkClmp); + Ybg = Ybg > blkThrs ? Ybg : Ybg + Math.pow(blkThrs - Ybg, blkClmp); + if (Math.abs(Ybg - Ytxt) < deltaYmin) return 0; + let out; + if (Ybg > Ytxt) { + const sapc = (Math.pow(Ybg, normBG) - Math.pow(Ytxt, normTXT)) * scaleBoW; + out = sapc < loClip ? 0 : sapc - loBoWoffset; + } else { + const sapc = (Math.pow(Ybg, revBG) - Math.pow(Ytxt, revTXT)) * scaleWoB; + out = sapc > -loClip ? 0 : sapc + loWoBoffset; + } + return out * 100; +} + +// deltaE-OK: Euclidean distance in OKLab. +function deltaE(aHex, bHex) { + const x = srgb2oklab(aHex), y = srgb2oklab(bHex); + return Math.hypot(x.L - y.L, x.a - y.a, x.b - y.b); +} + +// --- WCAG 2.x relative luminance + contrast (migrated from the page inline) --- +// rl reuses the canonical lin() above. On 8-bit channels lin's 0.04045 cutoff is +// byte-identical to the WCAG 0.03928 piecewise the inline copy used — no channel +// value falls between the two thresholds (10/255 = 0.0392, 11/255 = 0.0431) — so +// every #rrggbb contrast value is preserved exactly. +function rl(hex) { + const [R, G, B] = hex2rgb(hex); + return 0.2126 * lin(R / 255) + 0.7152 * lin(G / 255) + 0.0722 * lin(B / 255); +} + +function contrast(aHex, bHex) { + const L1 = rl(aHex), L2 = rl(bHex), hi = Math.max(L1, L2), lo = Math.min(L1, L2); + return (hi + 0.05) / (lo + 0.05); +} + +function rating(r) { return r >= 7 ? 'AAA' : r >= 4.5 ? 'AA' : 'FAIL'; } + +// --- HSV <-> sRGB for the color picker (migrated from the page inline) --- +function hsv2rgb(h, s, v) { + h = (h % 360 + 360) % 360 / 360; + const i = Math.floor(h * 6), f = h * 6 - i, p = v * (1 - s), q = v * (1 - f * s), t = v * (1 - (1 - f) * s); + let r, g, b; + switch (((i % 6) + 6) % 6) { + case 0: [r, g, b] = [v, t, p]; break; + case 1: [r, g, b] = [q, v, p]; break; + case 2: [r, g, b] = [p, v, t]; break; + case 3: [r, g, b] = [p, q, v]; break; + case 4: [r, g, b] = [t, p, v]; break; + default: [r, g, b] = [v, p, q]; + } + return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; +} + +function rgb2hsv(r, g, b) { + r /= 255; g /= 255; b /= 255; + const mx = Math.max(r, g, b), mn = Math.min(r, g, b), d = mx - mn; + let h = 0; + if (d) { + if (mx === r) h = ((g - b) / d + 6) % 6; + else if (mx === g) h = (b - r) / d + 2; + else h = (r - g) / d + 4; + h *= 60; + } + return [h, mx ? d / mx : 0, mx]; +} + +function rgb2hex(r, g, b) { + return '#' + [r, g, b].map(x => Math.max(0, Math.min(255, x)).toString(16).padStart(2, '0')).join(''); +} + +export { srgb2oklab, oklab2oklch, oklch2oklab, oklch2hex, apca, deltaE, hex2rgb, lin, rl, contrast, rating, hsv2rgb, rgb2hsv, rgb2hex }; diff --git a/scripts/theme-studio/dupre-revised.json b/scripts/theme-studio/dupre-revised.json new file mode 100644 index 00000000..89aa84e0 --- /dev/null +++ b/scripts/theme-studio/dupre-revised.json @@ -0,0 +1,10411 @@ +{ + "name": "dupre-revised", + "palette": [ + [ + "#000000", + "ground" + ], + [ + "#7a9abe", + "blue" + ], + [ + "#e8bd30", + "gold" + ], + [ + "#84b068", + "pistachio" + ], + [ + "#be9e74", + "tan" + ], + [ + "#d7849d", + "orchid pink" + ], + [ + "#de4949", + "terracotta" + ], + [ + "#cdced1", + "white" + ], + [ + "#a9b2bb", + "silver" + ], + [ + "#838d97", + "steel" + ], + [ + "#5e6770", + "pewter" + ], + [ + "#2f343a", + "gunmetal" + ], + [ + "#264364", + "navy" + ], + [ + "#1a1714", + "bg-dim" + ], + [ + "#c76666", + "red" + ], + [ + "#e52e2e", + "deep red" + ], + [ + "#7f00fe", + "violet" + ], + [ + "#eed376", + "yellow1" + ] + ], + "assignments": { + "bg": "#000000", + "p": "#cdced1", + "kw": "#7a9abe", + "bi": "#7a9abe", + "pp": "#7a9abe", + "fnd": "#a9b2bb", + "fnc": "#a9b2bb", + "dec": "#e8bd30", + "ty": "#a9b2bb", + "prop": "#7a9abe", + "con": "#84b068", + "num": "#84b068", + "str": "#d7849d", + "esc": "#84b068", + "re": "#a9b2bb", + "doc": "#d7849d", + "cm": "#a9b2bb", + "cmd": "#a9b2bb", + "var": "#e8bd30", + "op": "#a9b2bb", + "punc": "#a9b2bb" + }, + "bold": [ + "kw", + "fnd", + "ty" + ], + "italic": [ + "cm", + "cmd" + ], + "ui": { + "cursor": { + "fg": null, + "bg": "#a9b2bb" + }, + "region": { + "fg": null, + "bg": "#264364" + }, + "hl-line": { + "fg": null, + "bg": "#1a1714" + }, + "highlight": { + "fg": null, + "bg": "#2f343a" + }, + "mode-line": { + "fg": "#cdced1", + "bg": "#2f343a" + }, + "mode-line-inactive": { + "fg": "#838d97", + "bg": "#1a1714" + }, + "fringe": { + "fg": null, + "bg": "#000000" + }, + "line-number": { + "fg": "#5e6770", + "bg": null + }, + "line-number-current-line": { + "fg": "#e8bd30", + "bg": "#1a1714" + }, + "minibuffer-prompt": { + "fg": "#7a9abe", + "bg": null + }, + "isearch": { + "fg": "#000000", + "bg": "#7a9abe" + }, + "lazy-highlight": { + "fg": "#000000", + "bg": "#838d97" + }, + "isearch-fail": { + "fg": "#de4949", + "bg": null + }, + "show-paren-match": { + "fg": null, + "bg": "#264364" + }, + "show-paren-mismatch": { + "fg": "#000000", + "bg": "#de4949" + }, + "link": { + "fg": "#7a9abe", + "bg": null + }, + "error": { + "fg": "#de4949", + "bg": null + }, + "warning": { + "fg": "#e8bd30", + "bg": null + }, + "success": { + "fg": "#5d9b86", + "bg": null + }, + "vertical-border": { + "fg": "#2f343a", + "bg": null + } + }, + "packages": { + "org-mode": { + "org-document-title": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-document-info": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-document-info-keyword": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": "fixed-pitch", + "source": "user" + }, + "org-level-1": { + "fg": "#67809c", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-level-2": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-level-3": { + "fg": "#9b5fd0", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-level-4": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default", + "height": 1.1 + }, + "org-level-5": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-level-6": { + "fg": "#be9e74", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-level-7": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-level-8": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-headline-todo": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-headline-done": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-todo": { + "fg": "#cb6b4d", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-done": { + "fg": "#5d9b86", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-priority": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-tag": { + "fg": "#be9e74", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-tag-group": { + "fg": "#be9e74", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-special-keyword": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-drawer": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-property-value": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-checkbox": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-checkbox-statistics-todo": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-checkbox-statistics-done": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-warning": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-link": { + "fg": "#67809c", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-footnote": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-date": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-sexp-date": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-date-selected": { + "fg": "#000000", + "bg": "#e8bd30", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-target": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-macro": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-cite": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-cite-key": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-block": { + "fg": "#cdced1", + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-block-begin-line": { + "fg": "#5e6770", + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-block-end-line": { + "fg": "#5e6770", + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": "fixed-pitch", + "source": "default" + }, + "org-code": { + "fg": "#cb6b4d", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-verbatim": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-inline-src-block": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": "fixed-pitch", + "source": "default" + }, + "org-quote": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-verse": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-latex-and-related": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-table": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-table-header": { + "fg": "#cdced1", + "bg": "#2f343a", + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-table-row": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-formula": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-column": { + "fg": null, + "bg": "#2f343a", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-column-title": { + "fg": "#cdced1", + "bg": "#2f343a", + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-list-dt": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-meta-line": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "user" + }, + "org-ellipsis": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "user" + }, + "org-hide": { + "fg": "#000000", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-indent": { + "fg": "#000000", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-archived": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-default": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-dispatcher-highlight": { + "fg": "#e8bd30", + "bg": "#264364", + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-structure": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default", + "height": 1.1 + }, + "org-agenda-structure-secondary": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-structure-filter": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-date": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default", + "height": 1.05 + }, + "org-agenda-date-today": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default", + "height": 1.05 + }, + "org-agenda-date-weekend": { + "fg": "#838d97", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-date-weekend-today": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-current-time": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-done": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-dimmed-todo-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-calendar-event": { + "fg": "#cdced1", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-calendar-sexp": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-calendar-daterange": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-diary": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-clocking": { + "fg": null, + "bg": "#264364", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-column-dateline": { + "fg": null, + "bg": "#2f343a", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-restriction-lock": { + "fg": null, + "bg": "#de4949", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-filter-category": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-filter-effort": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-filter-regexp": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-agenda-filter-tags": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-scheduled": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-scheduled-today": { + "fg": null, + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-scheduled-previously": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-upcoming-deadline": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-upcoming-distant-deadline": { + "fg": "#be9e74", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-imminent-deadline": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-time-grid": { + "fg": "#be9e74", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-clock-overlay": { + "fg": null, + "bg": "#264364", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-mode-line-clock": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-mode-line-clock-overrun": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "magit": { + "magit-section-heading": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-section-secondary-heading": { + "fg": "#be9e74", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-section-heading-selection": { + "fg": "#e8bd30", + "bg": "#264364", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-section-highlight": { + "fg": null, + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-section-child-count": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-added": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-added-highlight": { + "fg": null, + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-removed": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-removed-highlight": { + "fg": "#de4949", + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-context": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-context-highlight": { + "fg": "#a9b2bb", + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-file-heading": { + "fg": "#cdced1", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-file-heading-highlight": { + "fg": "#cdced1", + "bg": "#1a1714", + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-file-heading-selection": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-hunk-heading": { + "fg": "#838d97", + "bg": "#2f343a", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-hunk-heading-highlight": { + "fg": "#cdced1", + "bg": "#2f343a", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-hunk-heading-selection": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-hunk-region": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-lines-heading": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-lines-boundary": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-base": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-base-highlight": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-our": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-our-highlight": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-their": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-their-highlight": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-conflict-heading": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-conflict-heading-highlight": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-revision-summary": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-revision-summary-highlight": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diff-whitespace-warning": { + "fg": null, + "bg": "#de4949", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diffstat-added": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-diffstat-removed": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-branch-current": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-branch-local": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-branch-remote": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-branch-remote-head": { + "fg": null, + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-branch-upstream": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-branch-warning": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-head": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-tag": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-hash": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-filename": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-dimmed": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-keyword": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-keyword-squash": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-refname": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-refname-stash": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-refname-wip": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-refname-pullreq": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-log-author": { + "fg": "#be9e74", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-log-date": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-log-graph": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-header-line": { + "fg": "#cdced1", + "bg": "#2f343a", + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-header-line-key": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-header-line-log-select": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-process-ok": { + "fg": null, + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-process-ng": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-mode-line-process": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-mode-line-process-error": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-bisect-good": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-bisect-bad": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-bisect-skip": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-blame-heading": { + "fg": "#838d97", + "bg": "#2f343a", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-blame-highlight": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-blame-hash": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-blame-name": { + "fg": "#be9e74", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-blame-date": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-blame-summary": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-blame-dimmed": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-blame-margin": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-cherry-equivalent": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-cherry-unmatched": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-signature-good": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-signature-bad": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-signature-untrusted": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-signature-expired": { + "fg": "#be9e74", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-signature-expired-key": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-signature-revoked": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-signature-error": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-reflog-commit": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-reflog-amend": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-reflog-merge": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-reflog-checkout": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-reflog-reset": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-reflog-rebase": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-reflog-cherry-pick": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-reflog-remote": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-reflog-other": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-sequence-pick": { + "fg": "#cdced1", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-sequence-stop": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-sequence-part": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-sequence-head": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-sequence-drop": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-sequence-done": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-sequence-onto": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-sequence-exec": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-left-margin": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "elfeed": { + "elfeed-search-date-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "elfeed-search-title-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "elfeed-search-unread-title-face": { + "fg": "#cdced1", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "elfeed-search-feed-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "elfeed-search-tag-face": { + "fg": "#be9e74", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "elfeed-search-unread-count-face": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "elfeed-search-filter-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "elfeed-search-last-update-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "elfeed-log-date-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "elfeed-log-error-level-face": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "elfeed-log-warn-level-face": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "elfeed-log-info-level-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "elfeed-log-debug-level-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "mu4e": { + "mu4e-title-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-context-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-modeline-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-ok-face": { + "fg": null, + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-warning-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-header-title-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-header-key-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-header-value-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-header-face": { + "fg": "#cdced1", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-header-highlight-face": { + "fg": null, + "bg": "#2f343a", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-header-marks-face": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-unread-face": { + "fg": "#cdced1", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-flagged-face": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-replied-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-forwarded-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-draft-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-trashed-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-moved-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-related-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-contact-face": { + "fg": "#cdced1", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-special-header-value-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-attach-number-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-url-number-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-link-face": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-cited-1-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-cited-2-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-cited-3-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-cited-4-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-cited-5-face": { + "fg": "#be9e74", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-cited-6-face": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-cited-7-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-footer-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-region-code": { + "fg": null, + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-system-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-highlight-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-compose-header-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "mu4e-compose-separator-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "ghostel": { + "ghostel-default": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-fake-cursor": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-fake-cursor-box": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-black": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-red": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-green": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-yellow": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-blue": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-magenta": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-cyan": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-white": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-bright-black": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-bright-red": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-bright-green": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-bright-yellow": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-bright-blue": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-bright-magenta": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-bright-cyan": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "ghostel-color-bright-white": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "dashboard": { + "dashboard-banner-logo-title": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dashboard-text-banner": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dashboard-heading": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dashboard-items-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dashboard-navigator": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dashboard-no-items-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dashboard-footer-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dashboard-footer-icon-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "lsp-mode": { + "lsp-signature-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-signature-highlight-function-argument": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-signature-posframe": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-face-highlight-read": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-face-highlight-write": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-face-highlight-textual": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-face-rename": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-rename-placeholder-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-inlay-hint-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-inlay-hint-parameter-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-inlay-hint-type-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-details-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-installation-buffer-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "lsp-installation-finished-buffer-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "git-gutter": { + "git-gutter:added": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "git-gutter:modified": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "git-gutter:deleted": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "git-gutter:unchanged": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "git-gutter:separator": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "flycheck": { + "flycheck-error": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-warning": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-info": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-fringe-error": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-fringe-warning": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-fringe-info": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-delimited-error": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-error-delimiter": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-error-list-error": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-error-list-warning": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-error-list-info": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-error-list-error-message": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-error-list-checker-name": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-error-list-column-number": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-error-list-line-number": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-error-list-filename": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-error-list-id": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-error-list-id-with-explainer": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-error-list-highlight": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "flycheck-verify-select-checker": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "dired": { + "dired-header": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dired-directory": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dired-symlink": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dired-broken-symlink": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dired-special": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dired-set-id": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dired-perm-write": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dired-mark": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dired-marked": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dired-flagged": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dired-ignored": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dired-warning": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "dirvish": { + "dirvish-inactive": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-free-space": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-hl-line": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-hl-line-inactive": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-file-modes": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-file-link-number": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-file-user-id": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-file-group-id": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-file-size": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-file-time": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-file-inode-number": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-file-device-number": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-subtree-guide": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-subtree-state": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-collapse-dir-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-collapse-empty-dir-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-collapse-file-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-emerge-group-title": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-media-info-heading": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-media-info-property-key": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-narrow-match-face-0": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-narrow-match-face-1": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-narrow-match-face-2": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-narrow-match-face-3": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-narrow-split": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-proc-running": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-proc-finished": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-proc-failed": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-git-commit-message-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-vc-added-state": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-vc-edited-state": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-vc-removed-state": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-vc-conflict-state": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-vc-locked-state": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-vc-missing-state": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-vc-needs-merge-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-vc-needs-update-state": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "dirvish-vc-unregistered-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "calibredb": { + "calibredb-search-header-library-name-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-search-header-library-path-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-search-header-total-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-search-header-filter-face": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-search-header-sort-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-search-header-highlight-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-id-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-title-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-author-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-format-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-size-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-tag-face": { + "fg": "#be9e74", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-date-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-mark-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-series-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-publisher-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-pubdate-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-language-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-comment-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-archive-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-favorite-face": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-file-face": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-ids-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-highlight-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-current-page-button-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-mouse-face": { + "fg": null, + "bg": "#2f343a", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-title-detailed-view-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "calibredb-edit-annotation-header-title-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "erc": { + "erc-header-line": { + "fg": "#cdced1", + "bg": "#2f343a", + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-timestamp-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-notice-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-default-face": { + "fg": "#cdced1", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-current-nick-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-my-nick-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-my-nick-prefix-face": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-nick-default-face": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-nick-prefix-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-button-nick-default-face": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-nick-msg-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-direct-msg-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-action-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-keyword-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-pal-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-fool-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-dangerous-host-face": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-error-face": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-input-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-prompt-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-command-indicator-face": { + "fg": "#838d97", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-information": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-button": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-bold-face": { + "fg": null, + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-italic-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-underline-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-inverse-face": { + "fg": "#000000", + "bg": "#a9b2bb", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-spoiler-face": { + "fg": "#000000", + "bg": "#2f343a", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-fill-wrap-merge-indicator-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-keep-place-indicator-arrow": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "erc-keep-place-indicator-line": { + "fg": null, + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "org-drill": { + "org-drill-hidden-cloze-face": { + "fg": "#000000", + "bg": "#838d97", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-drill-visible-cloze-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-drill-visible-cloze-hint-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "org-noter": { + "org-noter-notes-exist-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-noter-no-notes-exist-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "signel": { + "signel-timestamp-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "signel-my-msg-face": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "signel-other-msg-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "signel-error-face": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "pearl": { + "pearl-preamble-summary": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "pearl-editable-comment": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "pearl-readonly-comment": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "pearl-modified-highlight": { + "fg": null, + "bg": "#264364", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "pearl-modified-local": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "pearl-modified-unknown": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "slack": { + "slack-room-info-title-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-room-info-title-room-name-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-room-info-section-title-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-room-info-section-label-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-room-unread-face": { + "fg": "#cdced1", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-message-output-header": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-message-output-text": { + "fg": "#cdced1", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-message-output-reaction": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-message-output-reaction-pressed": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-message-deleted-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-new-message-marker-face": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-all-thread-buffer-thread-header-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-message-mention-face": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-message-mention-me-face": { + "fg": "#e8bd30", + "bg": "#264364", + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-message-mention-keyword-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-channel-button-face": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-mrkdwn-bold-face": { + "fg": null, + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-mrkdwn-italic-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-mrkdwn-code-face": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-mrkdwn-code-block-face": { + "fg": "#de4949", + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-mrkdwn-strike-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-mrkdwn-blockquote-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-mrkdwn-list-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-attachment-header": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-attachment-footer": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-attachment-pad": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-attachment-field-title": { + "fg": "#838d97", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-message-attachment-preview-header-face": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-preview-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-block-highlight-source-overlay-face": { + "fg": null, + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-message-action-face": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-message-action-primary-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-message-action-danger-face": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-button-block-element-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-button-primary-block-element-face": { + "fg": null, + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-button-danger-block-element-face": { + "fg": "#de4949", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-select-block-element-face": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-overflow-block-element-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-date-picker-block-element-face": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-dialog-title-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-dialog-element-label-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-dialog-element-hint-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-dialog-element-placeholder-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-dialog-element-error-face": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-dialog-submit-button-face": { + "fg": null, + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-dialog-cancel-button-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-dialog-select-element-input-face": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-user-active-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-user-dnd-face": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-user-profile-header-face": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-user-profile-property-name-face": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-profile-image-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-search-result-message-header-face": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-search-result-message-username-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-modeline-has-unreads-face": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-modeline-channel-has-unreads-face": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "slack-modeline-thread-has-unreads-face": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "telega": { + "telega-root-heading": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-tracking": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-unread-unmuted-modeline": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-username": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-user-online-status": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-user-non-online-status": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-secret-title": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-contact-birthdays-today": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-muted-count": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-unmuted-count": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-mention-count": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-has-chatbuf-brackets": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-delim-face": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-shadow": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-link": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-blue": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-red": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-msg-heading": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-msg-user-title": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-msg-self-title": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-msg-deleted": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-msg-sponsored": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-msg-inline-reply": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-msg-inline-forward": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-msg-inline-other": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-bold": { + "fg": null, + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-italic": { + "fg": null, + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-underline": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-strikethrough": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-code": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-pre": { + "fg": "#de4949", + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-blockquote": { + "fg": "#a9b2bb", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-mention": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-hashtag": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-cashtag": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-botcommand": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-texturl": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-entity-type-spoiler": { + "fg": "#2f343a", + "bg": "#2f343a", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-reaction": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-reaction-chosen": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-reaction-paid": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-reaction-paid-chosen": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-highlight-text-face": { + "fg": "#000000", + "bg": "#e8bd30", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-button-highlight": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-chat-prompt": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-chat-prompt-aux": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-chat-input-attachment": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-topic-button": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-filter-active": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-filter-button-active": { + "fg": "#000000", + "bg": "#e8bd30", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-filter-button-inactive": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-checklist-stats-done": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-checklist-stats-todo": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button-active": { + "fg": "#000000", + "bg": "#7a9abe", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button-default-active": { + "fg": "#000000", + "bg": "#a9b2bb", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button-default-passive": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button-primary-active": { + "fg": "#000000", + "bg": "#7a9abe", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button-primary-passive": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button-success-active": { + "fg": "#000000", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button-success-passive": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button-danger-active": { + "fg": "#000000", + "bg": "#de4949", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button-danger-passive": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button-ui-active": { + "fg": "#000000", + "bg": "#e8bd30", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button-ui-passive": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button2-active": { + "fg": "#000000", + "bg": "#7a9abe", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button2-passive": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-box-button2-white-foreground": { + "fg": "#cdced1", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-describe-item-title": { + "fg": "#838d97", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-describe-section-title": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-describe-subsection-title": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-enckey-00": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-enckey-01": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-enckey-10": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-enckey-11": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-palette-builtin-blue": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-palette-builtin-green": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-palette-builtin-orange": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-palette-builtin-purple": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-webpage-title": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-webpage-subtitle": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-webpage-header": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-webpage-subheader": { + "fg": "#e8bd30", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-webpage-outline": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-webpage-fixed": { + "fg": "#de4949", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-webpage-preformatted": { + "fg": "#de4949", + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-webpage-marked": { + "fg": "#000000", + "bg": "#e8bd30", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-webpage-strike-through": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-webpage-chat-link": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-link-preview-sitename": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "telega-link-preview-title": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "shr": { + "shr-h1": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default", + "height": 1.4 + }, + "shr-h2": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default", + "height": 1.2 + }, + "shr-h3": { + "fg": "#7a9abe", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "shr-h4": { + "fg": "#a9b2bb", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "shr-h5": { + "fg": "#838d97", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "shr-h6": { + "fg": "#5e6770", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "shr-text": { + "fg": "#cdced1", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "shr-link": { + "fg": "#7a9abe", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "shr-selected-link": { + "fg": "#e8bd30", + "bg": null, + "bold": true, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "shr-code": { + "fg": "#de4949", + "bg": "#1a1714", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "shr-mark": { + "fg": "#000000", + "bg": "#e8bd30", + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "shr-strike-through": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "shr-sup": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "shr-abbreviation": { + "fg": "#838d97", + "bg": null, + "bold": false, + "italic": true, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "shr-sliced-image": { + "fg": "#5e6770", + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "2048-game": { + "twentyfortyeight-face-1024": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "twentyfortyeight-face-128": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "twentyfortyeight-face-16": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "twentyfortyeight-face-2": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "twentyfortyeight-face-2048": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "twentyfortyeight-face-256": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "twentyfortyeight-face-32": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "twentyfortyeight-face-4": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "twentyfortyeight-face-512": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "twentyfortyeight-face-64": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "twentyfortyeight-face-8": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "alert": { + "alert-high-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "alert-low-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "alert-moderate-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "alert-normal-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "alert-trivial-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "alert-urgent-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "all-the-icons": { + "all-the-icons-blue": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-blue-alt": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-cyan": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-cyan-alt": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-dblue": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-dcyan": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-dgreen": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-dmaroon": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-dorange": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-dpink": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-dpurple": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-dred": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-dsilver": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-dyellow": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-green": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-lblue": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-lcyan": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-lgreen": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-lmaroon": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-lorange": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-lpink": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-lpurple": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-lred": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-lsilver": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-lyellow": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-maroon": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-orange": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-pink": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-purple": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-purple-alt": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-red": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-red-alt": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-silver": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "all-the-icons-yellow": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "company": { + "company-echo": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-echo-common": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-preview": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-preview-common": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-preview-search": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-annotation": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-annotation-selection": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-common": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-common-selection": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-deprecated": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-mouse": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-quick-access": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-quick-access-selection": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-scrollbar-thumb": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-scrollbar-track": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-search": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-search-selection": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-tooltip-selection": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "company-box": { + "company-box-annotation": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-box-background": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-box-candidate": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-box-numbers": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-box-scrollbar": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "company-box-selection": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "consult": { + "consult-async-failed": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-async-finished": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-async-running": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-async-split": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-bookmark": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-buffer": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-file": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-grep-context": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-help": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-highlight-mark": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-highlight-match": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-key": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-line-number": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-line-number-prefix": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-line-number-wrapped": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-narrow-indicator": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-preview-insertion": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-preview-line": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-preview-match": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "consult-separator": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "embark": { + "embark-collect-annotation": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "embark-collect-candidate": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "embark-collect-group-separator": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "embark-collect-group-title": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "embark-keybinding": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "embark-keybinding-repeat": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "embark-keymap": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "embark-selected": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "embark-target": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "embark-verbose-indicator-documentation": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "embark-verbose-indicator-shadowed": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "embark-verbose-indicator-title": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "emms": { + "emms-browser-album-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "emms-browser-albumartist-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "emms-browser-artist-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "emms-browser-composer-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "emms-browser-performer-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "emms-browser-track-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "emms-browser-year/genre-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "emms-metaplaylist-mode-current-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "emms-metaplaylist-mode-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "emms-playlist-selected-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "emms-playlist-track-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "flyspell-correct": { + "flyspell-correct-highlight-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "highlight-indent-guides": { + "highlight-indent-guides-character-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "highlight-indent-guides-even-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "highlight-indent-guides-odd-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "highlight-indent-guides-stack-character-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "highlight-indent-guides-stack-even-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "highlight-indent-guides-stack-odd-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "highlight-indent-guides-top-character-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "highlight-indent-guides-top-even-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "highlight-indent-guides-top-odd-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "hl-todo": { + "hl-todo": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "hl-todo-flymake-type": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "json-mode": { + "json-mode-object-name-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "llama": { + "llama-##-macro": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "llama-deleted-argument": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "llama-llama-macro": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "llama-mandatory-argument": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "llama-optional-argument": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "lv": { + "lv-separator": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "magit-section": { + "magit-left-margin": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-section-child-count": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-section-heading": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-section-heading-selection": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-section-highlight": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "magit-section-secondary-heading": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "malyon": { + "malyon-face-bold": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "malyon-face-error": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "malyon-face-italic": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "malyon-face-plain": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "malyon-face-reverse": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "marginalia": { + "marginalia-archive": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-char": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-date": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-documentation": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-file-name": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-file-owner": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-file-priv-dir": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-file-priv-exec": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-file-priv-link": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-file-priv-no": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-file-priv-other": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-file-priv-rare": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-file-priv-read": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-file-priv-write": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-function": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-installed": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-key": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-lighter": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-list": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-mode": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-modified": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-null": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-number": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-off": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-on": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-size": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-string": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-symbol": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-true": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-type": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-value": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "marginalia-version": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "markdown-mode": { + "markdown-blockquote-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-bold-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-code-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-comment-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-footnote-marker-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-footnote-text-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-gfm-checkbox-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-header-delimiter-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-header-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-header-face-1": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-header-face-2": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-header-face-3": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-header-face-4": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-header-face-5": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-header-face-6": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-header-rule-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-highlight-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-highlighting-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-hr-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-html-attr-name-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-html-attr-value-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-html-entity-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-html-tag-delimiter-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-html-tag-name-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-inline-code-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-italic-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-language-info-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-language-keyword-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-line-break-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-link-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-link-title-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-list-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-markup-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-math-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-metadata-key-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-metadata-value-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-missing-link-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-plain-url-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-pre-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-reference-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-strike-through-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-table-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "markdown-url-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "nerd-icons": { + "nerd-icons-blue": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-blue-alt": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-cyan": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-cyan-alt": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-dblue": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-dcyan": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-dgreen": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-dmaroon": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-dorange": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-dpink": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-dpurple": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-dred": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-dsilver": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-dyellow": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-green": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-lblue": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-lcyan": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-lgreen": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-lmaroon": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-lorange": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-lpink": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-lpurple": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-lred": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-lsilver": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-lyellow": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-maroon": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-orange": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-pink": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-purple": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-purple-alt": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-red": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-red-alt": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-silver": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "nerd-icons-yellow": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "nerd-icons-completion": { + "nerd-icons-completion-dir-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "orderless": { + "orderless-match-face-0": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "orderless-match-face-1": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "orderless-match-face-2": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "orderless-match-face-3": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "org-roam": { + "org-roam-dailies-calendar-note": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-roam-dim": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-roam-header-line": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-roam-olp": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-roam-preview-heading": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-roam-preview-heading-highlight": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-roam-preview-heading-selection": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-roam-preview-region": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-roam-title": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "org-superstar": { + "org-superstar-first": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-superstar-header-bullet": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-superstar-item": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "org-superstar-leading": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "prescient": { + "prescient-primary-highlight": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "prescient-secondary-highlight": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "rainbow-delimiters": { + "rainbow-delimiters-base-error-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "rainbow-delimiters-base-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "rainbow-delimiters-depth-1-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "rainbow-delimiters-depth-2-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "rainbow-delimiters-depth-3-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "rainbow-delimiters-depth-4-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "rainbow-delimiters-depth-5-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "rainbow-delimiters-depth-6-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "rainbow-delimiters-depth-7-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "rainbow-delimiters-depth-8-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "rainbow-delimiters-depth-9-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "rainbow-delimiters-mismatched-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "rainbow-delimiters-unmatched-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "symbol-overlay": { + "symbol-overlay-default-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "symbol-overlay-face-1": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "symbol-overlay-face-2": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "symbol-overlay-face-3": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "symbol-overlay-face-4": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "symbol-overlay-face-5": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "symbol-overlay-face-6": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "symbol-overlay-face-7": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "symbol-overlay-face-8": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "tmr": { + "tmr-description": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "tmr-duration": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "tmr-end-time": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "tmr-finished": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "tmr-is-acknowledged": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "tmr-must-be-acknowledged": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "tmr-start-time": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "tmr-tabulated-acknowledgement": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "tmr-tabulated-description": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "tmr-tabulated-end-time": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "tmr-tabulated-remaining-time": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "tmr-tabulated-start-time": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "transient": { + "transient-active-infix": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-argument": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-delimiter": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-disabled-suffix": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-enabled-suffix": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-heading": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-higher-level": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-inactive-argument": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-inactive-value": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-inapt-argument": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-inapt-suffix": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-key": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-key-exit": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-key-noop": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-key-recurse": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-key-return": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-key-stack": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-key-stay": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-mismatched-key": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-nonstandard-key": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-unreachable": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-unreachable-key": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "transient-value": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "vertico": { + "vertico-current": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "vertico-group-separator": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "vertico-group-title": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "vertico-multiline": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "web-mode": { + "web-mode-annotation-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-annotation-html-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-annotation-tag-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-annotation-type-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-annotation-value-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-block-attr-name-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-block-attr-value-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-block-comment-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-block-control-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-block-delimiter-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-block-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-block-string-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-bold-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-builtin-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-comment-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-comment-keyword-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-constant-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-css-at-rule-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-css-color-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-css-comment-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-css-function-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-css-priority-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-css-property-name-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-css-pseudo-class-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-css-selector-class-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-css-selector-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-css-selector-tag-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-css-string-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-css-variable-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-current-column-highlight-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-current-element-highlight-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-doctype-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-error-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-filter-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-folded-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-function-call-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-function-name-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-html-attr-custom-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-html-attr-engine-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-html-attr-equal-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-html-attr-name-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-html-attr-value-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-html-entity-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-html-tag-bracket-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-html-tag-custom-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-html-tag-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-html-tag-namespaced-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-html-tag-unclosed-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-inlay-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-interpolate-color1-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-interpolate-color2-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-interpolate-color3-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-interpolate-color4-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-italic-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-javascript-comment-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-javascript-string-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-json-comment-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-json-context-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-json-key-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-json-string-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-jsx-depth-1-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-jsx-depth-2-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-jsx-depth-3-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-jsx-depth-4-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-jsx-depth-5-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-keyword-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-param-name-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-part-comment-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-part-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-part-string-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-preprocessor-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-script-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-sql-keyword-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-string-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-style-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-symbol-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-type-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-underline-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-variable-name-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-warning-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "web-mode-whitespace-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + }, + "yasnippet": { + "yas--field-debug-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + }, + "yas-field-highlight-face": { + "fg": null, + "bg": null, + "bold": false, + "italic": false, + "underline": false, + "strike": false, + "inherit": null, + "source": "default" + } + } + } +}
\ No newline at end of file diff --git a/scripts/theme-studio/dupre.json b/scripts/theme-studio/dupre.json new file mode 100644 index 00000000..f3a46990 --- /dev/null +++ b/scripts/theme-studio/dupre.json @@ -0,0 +1,175 @@ +{ + "name": "dupre", + "palette": [ + [ + "#67809c", + "blue" + ], + [ + "#e8bd30", + "gold" + ], + [ + "#9b5fd0", + "regal" + ], + [ + "#2ba178", + "emerald" + ], + [ + "#5d9b86", + "sage" + ], + [ + "#cb6b4d", + "terracotta" + ], + [ + "#be9e74", + "tan" + ], + [ + "#cdced1", + "white" + ], + [ + "#a9b2bb", + "silver" + ], + [ + "#838d97", + "steel" + ], + [ + "#5e6770", + "pewter" + ], + [ + "#2f343a", + "gunmetal" + ], + [ + "#264364", + "navy" + ], + [ + "#0d0b0a", + "ground" + ], + [ + "#1a1714", + "bg-dim" + ] + ], + "assignments": { + "bg": "#0d0b0a", + "p": "#cdced1", + "kw": "#67809c", + "bi": "#67809c", + "pp": "#67809c", + "fnd": "#a9b2bb", + "fnc": "#a9b2bb", + "dec": "#e8bd30", + "ty": "#9b5fd0", + "prop": "#838d97", + "con": "#cb6b4d", + "num": "#cb6b4d", + "str": "#5d9b86", + "esc": "#cb6b4d", + "re": "#5d9b86", + "doc": "#5d9b86", + "cm": "#be9e74", + "cmd": "#a9b2bb", + "var": "#e8bd30", + "op": "#a9b2bb", + "punc": "#a9b2bb" + }, + "bold": [ + "kw", + "fnd" + ], + "italic": [], + "ui": { + "cursor": { + "fg": null, + "bg": "#a9b2bb" + }, + "region": { + "fg": null, + "bg": "#264364" + }, + "hl-line": { + "fg": null, + "bg": "#1a1714" + }, + "highlight": { + "fg": null, + "bg": "#2f343a" + }, + "mode-line": { + "fg": "#cdced1", + "bg": "#2f343a" + }, + "mode-line-inactive": { + "fg": "#838d97", + "bg": "#1a1714" + }, + "fringe": { + "fg": null, + "bg": "#0d0b0a" + }, + "line-number": { + "fg": "#5e6770", + "bg": null + }, + "line-number-current-line": { + "fg": "#e8bd30", + "bg": "#1a1714" + }, + "minibuffer-prompt": { + "fg": "#67809c", + "bg": null + }, + "isearch": { + "fg": "#0d0b0a", + "bg": "#e8bd30" + }, + "lazy-highlight": { + "fg": "#0d0b0a", + "bg": "#838d97" + }, + "isearch-fail": { + "fg": "#cb6b4d", + "bg": null + }, + "show-paren-match": { + "fg": null, + "bg": "#264364" + }, + "show-paren-mismatch": { + "fg": "#0d0b0a", + "bg": "#cb6b4d" + }, + "link": { + "fg": "#67809c", + "bg": null + }, + "error": { + "fg": "#cb6b4d", + "bg": null + }, + "warning": { + "fg": "#e8bd30", + "bg": null + }, + "success": { + "fg": "#5d9b86", + "bg": null + }, + "vertical-border": { + "fg": "#2f343a", + "bg": null + } + } +}
\ No newline at end of file diff --git a/scripts/theme-studio/generate.py b/scripts/theme-studio/generate.py index c34b34b6..285bb470 100644 --- a/scripts/theme-studio/generate.py +++ b/scripts/theme-studio/generate.py @@ -1,5 +1,13 @@ import json, os HERE=os.path.dirname(os.path.abspath(__file__)) +# Pure color-math core, inlined verbatim into the page so the browser runs the +# same code the Node tests import (one source of truth). Strip the ES-module +# `export` line(s) — a top-level export is a syntax error in a classic <script>. +# test-colormath.mjs applies the identical strip and asserts the page carries this +# body verbatim (inline-integrity), so the two copies cannot drift. +COLORMATH_BODY='\n'.join( + l for l in open(os.path.join(HERE,'colormath.js')).read().splitlines() + if not l.startswith('export')).rstrip() ns={} src=open(os.path.join(HERE,'samples.py')).read() exec(src[:src.index('cols=')], ns) @@ -405,7 +413,9 @@ HTML = """<!doctype html><meta charset=utf-8><title>theme-studio</title> .svcur{position:absolute;width:16px;height:16px;border:2px solid #fff;border-radius:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #0008;pointer-events:none} .hue{position:relative;width:34px;height:320px;border-radius:4px;cursor:ns-resize;background:linear-gradient(to bottom,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)} .huecur{position:absolute;left:-2px;right:-2px;height:4px;background:#fff;border:1px solid #0008;transform:translateY(-50%);pointer-events:none} - .pinfo{display:flex;justify-content:space-between;margin:10px 2px 8px;font:12pt monospace;color:#cdced1} + .pinfo{display:flex;justify-content:space-between;margin:10px 2px 4px;font:12pt monospace;color:#cdced1} + .pinfo2{display:flex;justify-content:space-between;margin:0 2px 9px;font:10pt monospace;color:#9aa3ad} + .pinfo2 span{cursor:default} .pkchips{display:flex;flex-wrap:wrap;gap:5px} .pkchips .pc{width:28px;height:28px;border-radius:3px;border:1px solid #555;cursor:pointer} .palctl button,.filebar button,.fbtn{background:#252321;color:#e8bd30;border:1px solid #3a3a3a;border-radius:4px;padding:6px 12px;font:10pt monospace;cursor:pointer} #palmsg{font:10pt monospace;opacity:0;transition:opacity .35s;margin-left:6px} @@ -449,6 +459,7 @@ HTML = """<!doctype html><meta charset=utf-8><title>theme-studio</title> <div id="hue" class="hue"><div id="huecur" class="huecur"></div></div> </div> <div class="pinfo"><span id="pkhex">#888888</span><span id="pkcon"></span></div> + <div class="pinfo2"><span id="pkoklch" title="OKLCH perceptual coordinates: lightness L (0..1), chroma C, hue H in degrees"></span><span id="pkapca"></span></div> <div class="pmode">limit <button data-m="any" class="on">any</button><button data-m="aa">AA+</button><button data-m="aaa">AAA</button></div> <div id="pkchips" class="pkchips"></div> </div> @@ -513,11 +524,11 @@ function packagesForExport(map){const out={};for(const app in map){const faces={ function mergePackagesInto(map,pkgs){if(!pkgs)return;for(const app in pkgs){if(!map[app])map[app]={};for(const face in pkgs[app]){const f=pkgs[app][face]||{};map[app][face]={fg:f.fg??null,bg:f.bg??null,bold:!!f.bold,italic:!!f.italic,underline:!!f.underline,strike:!!f.strike,inherit:f.inherit??null,height:f.height||1,source:f.source||'user'};}}} let PKGMAP=seedPkgmap(); function esc(t){return t.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');} -function lin(c){c/=255;return c<=0.03928?c/12.92:Math.pow((c+0.055)/1.055,2.4);} -function rl(h){return 0.2126*lin(parseInt(h.substr(1,2),16))+0.7152*lin(parseInt(h.substr(3,2),16))+0.0722*lin(parseInt(h.substr(5,2),16));} +// Pure color-math core (lin/rl/contrast/rating/hsv2rgb/rgb2hsv/hex2rgb/rgb2hex, +// plus OKLab/OKLCH/APCA/deltaE), inlined verbatim from colormath.js. normHex, +// textOn, and ratingColor stay below as UI-boundary helpers. +COLORMATH_J function textOn(h){const L=rl(h);return ((L+0.05)/0.05)>(1.05/(L+0.05))?'#000':'#fff';} -function contrast(a,b){const L1=rl(a),L2=rl(b),hi=Math.max(L1,L2),lo=Math.min(L1,L2);return (hi+0.05)/(lo+0.05);} -function rating(r){return r>=7?'AAA':r>=4.5?'AA':'FAIL';} function ratingColor(r){return r>=7?'#5d9b86':r>=4.5?'#a9b2bb':'#cb6b4d';} function cid(l){return l.replace(/\\W/g,'');} function buildLangSel(){const s=document.getElementById('langsel');s.innerHTML='';for(const lang in SAMPLES){const o=document.createElement('option');o.value=lang;o.textContent=lang;s.appendChild(o);}} @@ -603,21 +614,19 @@ function updateColor(){ } function normHex(s){s=s.trim();if(/^[0-9a-fA-F]{6}$/.test(s))s='#'+s;return /^#[0-9a-fA-F]{6}$/.test(s)?s.toLowerCase():null;} function curHex(){return normHex(document.getElementById('newhexstr').value)||'#888888';} -function hsv2rgb(h,s,v){h=(h%360+360)%360/360;const i=Math.floor(h*6),f=h*6-i,p=v*(1-s),q=v*(1-f*s),t=v*(1-(1-f)*s);let r,g,b;switch(((i%6)+6)%6){case 0:[r,g,b]=[v,t,p];break;case 1:[r,g,b]=[q,v,p];break;case 2:[r,g,b]=[p,v,t];break;case 3:[r,g,b]=[p,q,v];break;case 4:[r,g,b]=[t,p,v];break;default:[r,g,b]=[v,p,q];}return[Math.round(r*255),Math.round(g*255),Math.round(b*255)];} -function rgb2hsv(r,g,b){r/=255;g/=255;b/=255;const mx=Math.max(r,g,b),mn=Math.min(r,g,b),d=mx-mn;let h=0;if(d){if(mx===r)h=((g-b)/d+6)%6;else if(mx===g)h=(b-r)/d+2;else h=(r-g)/d+4;h*=60;}return[h,mx?d/mx:0,mx];} -function hex2rgb(h){return[parseInt(h.substr(1,2),16),parseInt(h.substr(3,2),16),parseInt(h.substr(5,2),16)];} -function rgb2hex(r,g,b){return '#'+[r,g,b].map(x=>Math.max(0,Math.min(255,x)).toString(16).padStart(2,'0')).join('');} let pkH=0,pkS=0,pkV=0.5,pickerOn=false; let pkMode='any'; function pkThresh(){return pkMode==='aa'?4.5:pkMode==='aaa'?7:0;} function drawMask(){const cv=document.getElementById('svmask');if(!cv)return;const sv=document.getElementById('sv'),w=cv.width=sv.clientWidth,h=cv.height=sv.clientHeight,ctx=cv.getContext('2d');ctx.clearRect(0,0,w,h);const T=pkThresh();if(!T)return;ctx.fillStyle='rgba(8,7,6,0.66)';const step=4;for(let x=0;x<w;x+=step){const S=x/w;for(let y=0;y<h;y+=step){const V=1-y/h,[r,g,b]=hsv2rgb(pkH,S,V);if(contrast(rgb2hex(r,g,b),MAP['bg'])<T)ctx.fillRect(x,y,step,step);}}} function paintPicker(){const sv=document.getElementById('sv');if(!sv)return;sv.style.background=`linear-gradient(to top,#000,rgba(0,0,0,0)),linear-gradient(to right,#fff,rgba(255,255,255,0)),hsl(${pkH},100%,50%)`;const w=sv.clientWidth,h=sv.clientHeight,hh=document.getElementById('hue').clientHeight;document.getElementById('svcur').style.left=(pkS*w)+'px';document.getElementById('svcur').style.top=((1-pkV)*h)+'px';document.getElementById('huecur').style.top=((pkH/360)*hh)+'px';drawMask();} -function pkReadout(h){const e=document.getElementById('pkhex');if(e)e.textContent=h;const c=document.getElementById('pkcon');if(c){const r=contrast(h,MAP['bg']);c.textContent=r.toFixed(1)+' '+rating(r);c.style.color=ratingColor(r);}} +function pkReadout(h){const e=document.getElementById('pkhex');if(e)e.textContent=h;const c=document.getElementById('pkcon');if(c){const r=contrast(h,MAP['bg']);c.textContent=r.toFixed(1)+' '+rating(r);c.style.color=ratingColor(r);} + const o=document.getElementById('pkoklch');if(o){const lch=oklab2oklch(srgb2oklab(h));o.textContent='OKLCH '+lch.L.toFixed(3)+' '+lch.C.toFixed(3)+' '+Math.round(lch.H)+'\\u00b0';} + const a=document.getElementById('pkapca');if(a){const lc=apca(h,MAP['bg']);a.textContent='APCA Lc '+lc.toFixed(0);a.title='APCA Lc '+lc.toFixed(1)+' (APCA-W3 0.1.9), text on the ground color. Positive = dark text on a light background, negative = light text on a dark background.';}} function syncHex(){const v=normHex(document.getElementById('newhexstr').value);if(!v)return;document.getElementById('swatch').style.background=v;[pkH,pkS,pkV]=rgb2hsv(...hex2rgb(v));if(pickerOn)paintPicker();pkReadout(v);} function setHex(h){h=normHex(h)||h;document.getElementById('newhexstr').value=h;document.getElementById('swatch').style.background=h;[pkH,pkS,pkV]=rgb2hsv(...hex2rgb(h));if(pickerOn)paintPicker();pkReadout(h);} function pkSet(){const hex=rgb2hex(...hsv2rgb(pkH,pkS,pkV));document.getElementById('newhexstr').value=hex;document.getElementById('swatch').style.background=hex;paintPicker();pkReadout(hex);} function buildPkChips(){const c=document.getElementById('pkchips');if(!c)return;c.innerHTML='';const T=pkThresh();PALETTE.forEach(([hex,name])=>{const s=document.createElement('div');s.className='pc';s.style.background=hex;s.title=name+' '+hex;const ok=!T||contrast(hex,MAP['bg'])>=T;if(!ok){s.style.opacity='0.22';s.title+=' (below '+pkMode.toUpperCase()+')';}s.onclick=()=>{if(ok)setHex(hex);};c.appendChild(s);});} -function openPicker(){pickerOn=true;[pkH,pkS,pkV]=rgb2hsv(...hex2rgb(curHex()));buildPkChips();paintPicker();pkReadout(curHex());document.getElementById('picker').style.display='block';setTimeout(()=>document.addEventListener('pointerdown',pkOutside),0);} +function openPicker(){pickerOn=true;[pkH,pkS,pkV]=rgb2hsv(...hex2rgb(curHex()));buildPkChips();document.getElementById('picker').style.display='block';paintPicker();pkReadout(curHex());setTimeout(()=>document.addEventListener('pointerdown',pkOutside),0);} function closePicker(){if(!pickerOn)return;pickerOn=false;const p=document.getElementById('picker');if(p)p.style.display='none';document.removeEventListener('pointerdown',pkOutside);} function pkOutside(e){if(!e.target.closest('#picker')&&!e.target.closest('#swatch'))closePicker();} function pkDrag(el,fn){el.addEventListener('pointerdown',e=>{e.preventDefault();fn(e);const mv=ev=>fn(ev),up=()=>{document.removeEventListener('pointermove',mv);document.removeEventListener('pointerup',up);};document.addEventListener('pointermove',mv);document.addEventListener('pointerup',up);});} @@ -1108,9 +1117,21 @@ function pkgSelftest(){ } if(location.hash==='#selftest')pkgSelftest(); if(location.hash.startsWith('#pick')){openPicker();const m=location.hash.slice(5);if(m){const b=document.querySelector('.pmode button[data-m="'+m+'"]');if(b)b.click();}} +if(location.hash==='#cursortest'){document.getElementById('newhexstr').value='#67809c';openPicker();const sc=document.getElementById('svcur'),hc=document.getElementById('huecur');const L=parseFloat(sc.style.left||'0'),T=parseFloat(sc.style.top||'0'),H=parseFloat(hc.style.top||'0');const ok=L>1&&T>1&&H>1;document.title='CURSORTEST '+(ok?'PASS':'FAIL');const d=document.createElement('div');d.id='cursortest';d.textContent='CURSORTEST '+(ok?'PASS':'FAIL')+' left='+sc.style.left+' top='+sc.style.top+' hue='+hc.style.top;document.body.appendChild(d);} if(location.hash.startsWith('#app')){const ap=location.hash.slice(4),s=document.getElementById('appsel');if(s&&ap){s.value=ap;pkgChanged();}} +if(location.hash==='#readouttest'){const hex='#67809c';document.getElementById('newhexstr').value=hex;openPicker();pkReadout(hex); + const o=document.getElementById('pkoklch').textContent,a=document.getElementById('pkapca').textContent,w=document.getElementById('pkcon').textContent; + const lch=oklab2oklch(srgb2oklab(hex)); + const expO='OKLCH '+lch.L.toFixed(3)+' '+lch.C.toFixed(3)+' '+Math.round(lch.H)+'\\u00b0'; + const expA='APCA Lc '+apca(hex,MAP['bg']).toFixed(0); + const r=contrast(hex,MAP['bg']),expW=r.toFixed(1)+' '+rating(r); + const wired=o===expO&&a===expA&&w===expW; + const sane=Math.abs(lch.L-0.591)<0.01&&Math.abs(lch.C-0.052)<0.01&&Math.abs(lch.H-251.6)<2; + const ok=wired&&sane;document.title='READOUTTEST '+(ok?'PASS':'FAIL'); + const d=document.createElement('div');d.id='readouttest';d.textContent='READOUTTEST '+(ok?'PASS':'FAIL')+' oklch='+o+' | apca='+a+' | wcag='+w;document.body.appendChild(d);} </script>""" -HTML=(HTML.replace("SAMPLES_J",json.dumps(SAMPLES)) +HTML=(HTML.replace("COLORMATH_J",COLORMATH_BODY) + .replace("SAMPLES_J",json.dumps(SAMPLES)) .replace("PALETTE_J",json.dumps(PALETTE)).replace("CATS_J",json.dumps(CATS)) .replace("UIFACES_J",json.dumps(UI_FACES)).replace("UIMAP_J",json.dumps(UIMAP)).replace("APPS_J",json.dumps(APPS)) .replace("BOLD_J",json.dumps(BOLD)).replace("MAP_J",json.dumps(MAP))) diff --git a/scripts/theme-studio/test-colormath.mjs b/scripts/theme-studio/test-colormath.mjs new file mode 100644 index 00000000..2e929b7b --- /dev/null +++ b/scripts/theme-studio/test-colormath.mjs @@ -0,0 +1,149 @@ +// Unit tests for the pure color-math core (colormath.js). +// Run: node --test scripts/theme-studio/ +// Run with coverage: node --test --experimental-test-coverage scripts/theme-studio/ +// +// Fixtures are from the perceptual-color-metrics spec: OKLab via Ottosson's +// reference, APCA via APCA-W3 0.1.9, deltaE via OKLab Euclidean distance. + +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { + srgb2oklab, oklab2oklch, oklch2hex, apca, deltaE, + hex2rgb, rl, contrast, rating, hsv2rgb, rgb2hsv, rgb2hex, +} from './colormath.js'; + +const close = (a, b, eps = 0.005) => Math.abs(a - b) <= eps; +const here = fileURLToPath(new URL('.', import.meta.url)); +// Same export-strip generate.py applies before inlining (drop `export` lines, rstrip). +const stripExports = (s) => + s.split('\n').filter((l) => !l.startsWith('export')).join('\n').replace(/\s+$/, ''); + +test('srgb2oklab achromatic anchors', () => { + const w = srgb2oklab('#ffffff'); + assert.ok(close(w.L, 1.0), `white L ${w.L}`); + assert.ok(close(w.a, 0) && close(w.b, 0), `white a/b ${w.a},${w.b}`); + const k = srgb2oklab('#000000'); + assert.ok(close(k.L, 0), `black L ${k.L}`); +}); + +test('OKLCH chromatic fixtures (red, dupre-blue)', () => { + const red = oklab2oklch(srgb2oklab('#ff0000')); + assert.ok(close(red.L, 0.628) && close(red.C, 0.258) && close(red.H, 29.2, 1), + `red ${JSON.stringify(red)}`); + const blue = oklab2oklch(srgb2oklab('#67809c')); + assert.ok(close(blue.L, 0.591) && close(blue.C, 0.052) && close(blue.H, 251.6, 1), + `dupre-blue ${JSON.stringify(blue)}`); +}); + +test('round-trip srgb -> oklch -> hex preserves the color', () => { + for (const h of ['#67809c', '#e8bd30', '#9b5fd0', '#5d9b86', '#cb6b4d']) { + const lab = srgb2oklab(h); + const c = oklab2oklch(lab); + const back = srgb2oklab(oklch2hex(c.L, c.C, c.H).hex); + assert.ok(close(lab.L, back.L) && close(lab.a, back.a) && close(lab.b, back.b), + `roundtrip ${h}`); + } +}); + +test('APCA both polarities (pinned black/white fixtures)', () => { + assert.ok(close(apca('#000000', '#ffffff'), 106.0, 0.5), + `dark-on-light ${apca('#000000', '#ffffff')}`); + assert.ok(close(apca('#ffffff', '#000000'), -107.9, 0.5), + `light-on-dark ${apca('#ffffff', '#000000')}`); + // Chromatic fixture: catches rounded-coefficient drift that black/white can't. + // Sign is positive (dark-ish text on a light bg). + assert.ok(apca('#67809c', '#ffffff') > 0, 'chromatic apca sign'); +}); + +test('deltaE-OK identity and ordering against the 0.02 threshold', () => { + assert.equal(deltaE('#67809c', '#67809c'), 0); + assert.ok(deltaE('#000000', '#ffffff') > 0); + const near = deltaE('#67809c', '#69829e'); // barely-different blue + const far = deltaE('#67809c', '#e8bd30'); // blue vs gold + assert.ok(near < 0.02, `near ${near}`); + assert.ok(far > 0.1, `far ${far}`); +}); + +test('gamut clamp preserves L/H, reduces C, flags clamped', () => { + const oog = oklch2hex(0.6, 0.5, 30); // very high chroma -> out of sRGB + assert.equal(oog.clamped, true); + const got = oklab2oklch(srgb2oklab(oog.hex)); + assert.ok(close(got.L, 0.6, 0.02), `L preserved ${got.L}`); + assert.ok(close(got.H, 30, 2), `H preserved ${got.H}`); + assert.ok(got.C < 0.5, `C reduced ${got.C}`); + const ing = oklch2hex(0.591, 0.052, 251.6); // in gamut + assert.equal(ing.clamped, false); +}); + +test('hex2rgb parses channels', () => { + assert.deepEqual(hex2rgb('#000000'), [0, 0, 0]); + assert.deepEqual(hex2rgb('#ffffff'), [255, 255, 255]); + assert.deepEqual(hex2rgb('#67809c'), [0x67, 0x80, 0x9c]); +}); + +test('WCAG relative luminance anchors', () => { + assert.ok(close(rl('#ffffff'), 1.0, 1e-9), `white ${rl('#ffffff')}`); + assert.ok(close(rl('#000000'), 0.0, 1e-9), `black ${rl('#000000')}`); + assert.ok(rl('#ff0000') < rl('#00ff00'), 'green brighter than red'); // 0.2126 vs 0.7152 +}); + +test('WCAG contrast: symmetry, identity, and known extremes', () => { + assert.ok(close(contrast('#000000', '#ffffff'), 21, 1e-6), 'black/white = 21:1'); + assert.equal(contrast('#67809c', '#67809c'), 1); // identical colors + assert.ok(close(contrast('#0d0b0a', '#67809c'), contrast('#67809c', '#0d0b0a'), 1e-12), + 'order-independent'); + // dupre keyword-blue on ground, a real palette pair (sanity, not a hand-typed number). + assert.ok(contrast('#67809c', '#0d0b0a') > 4.5, 'dupre blue clears AA on ground'); +}); + +test('rating bands at the AA/AAA boundaries', () => { + assert.equal(rating(7.0), 'AAA'); + assert.equal(rating(6.99), 'AA'); + assert.equal(rating(4.5), 'AA'); + assert.equal(rating(4.49), 'FAIL'); + assert.equal(rating(0), 'FAIL'); +}); + +test('hsv2rgb primaries and achromatic edges', () => { + assert.deepEqual(hsv2rgb(0, 1, 1), [255, 0, 0]); + assert.deepEqual(hsv2rgb(120, 1, 1), [0, 255, 0]); + assert.deepEqual(hsv2rgb(240, 1, 1), [0, 0, 255]); + assert.deepEqual(hsv2rgb(0, 0, 1), [255, 255, 255]); // s=0 -> grey (white) + assert.deepEqual(hsv2rgb(0, 0, 0), [0, 0, 0]); // v=0 -> black + assert.deepEqual(hsv2rgb(360, 1, 1), [255, 0, 0]); // hue wraps +}); + +test('rgb2hsv inverts hsv2rgb (saturation/value), hue for chromatic inputs', () => { + assert.deepEqual(rgb2hsv(255, 0, 0), [0, 1, 1]); + assert.deepEqual(rgb2hsv(0, 0, 0), [0, 0, 0]); // black: h and s undefined -> 0 + const [h, s, v] = rgb2hsv(0, 255, 0); + assert.ok(close(h, 120, 1e-9) && s === 1 && v === 1, `green hsv ${h},${s},${v}`); +}); + +test('hsv <-> rgb round-trip property over random colors', () => { + let seed = 1234567; // deterministic LCG: no Math.random, repeatable failures + const rnd = () => (seed = (seed * 1103515245 + 12345) & 0x7fffffff) / 0x7fffffff; + for (let i = 0; i < 500; i++) { + const rgb = [Math.floor(rnd() * 256), Math.floor(rnd() * 256), Math.floor(rnd() * 256)]; + const [h, s, v] = rgb2hsv(...rgb); + assert.deepEqual(hsv2rgb(h, s, v), rgb, `round-trip ${rgb}`); + } +}); + +test('rgb2hex formats and clamps out-of-range channels', () => { + assert.equal(rgb2hex(0, 0, 0), '#000000'); + assert.equal(rgb2hex(255, 255, 255), '#ffffff'); + assert.equal(rgb2hex(0x67, 0x80, 0x9c), '#67809c'); + assert.equal(rgb2hex(-5, 300, 128), '#00ff80'); // clamps below 0 and above 255 +}); + +// Guards the one-source-of-truth contract: the page must carry colormath.js's +// body (sans exports) verbatim, so the inlined copy and the tested module cannot +// drift. Requires `python3 generate.py` to have run first. +test('inline-integrity: theme-studio.html contains the colormath.js body verbatim', () => { + const body = stripExports(readFileSync(here + 'colormath.js', 'utf8')); + const html = readFileSync(here + 'theme-studio.html', 'utf8'); + assert.ok(html.includes(body), 'generated page is missing the colormath.js body verbatim'); +}); diff --git a/scripts/theme-studio/theme-coloring-guide.org b/scripts/theme-studio/theme-coloring-guide.org new file mode 100644 index 00000000..170ad708 --- /dev/null +++ b/scripts/theme-studio/theme-coloring-guide.org @@ -0,0 +1,473 @@ +#+TITLE: Usual Color Theme Rules +#+AUTHOR: Craig Jennings +#+DATE: 2026-06-08 +#+STARTUP: showall + +* How to use this guide + +This guide has one idea under it: color by the role a thing plays for the +reader, spend attention deliberately, and draw everything from one disciplined +palette. Everything else is that idea applied. + +It runs general to specific: + +1. *Principles*: the seven laws that generate the rest. +2. *Roles and the seed table*: the reader-roles the principles color, and the + single table that says how each role is treated. This is the executable core. +3. *The tiers*: syntax, UI faces, and package faces are the same roles applied + to three sets of Emacs faces. Each tier's rules derive from the principles, + not apart from them. +4. *Cross-tier practice*: weight, contrast, accessibility, and the checks that + apply everywhere. + +If you only read one thing, read the principles and the seed table. The tiers +are worked examples. + +* Principles + +1. *Color by reader-role, not by source category.* A color means "these things + play the same role while reading." The parser's category is irrelevant; the + reader's intent is everything. The theme should make control flow, + definitions, literals, comments, and errors easy to scan without making every + token compete for attention. + +2. *One disciplined palette; relatedness lives inside a hue family.* Prefer six + to eight stable accents over one color per category, and reuse each for the + same role everywhere. Related roles share a hue and separate by lightness, + chroma, or weight rather than taking unrelated colors. The six to eight are + hue families, not swatches: each family carries one to three shades (a keyword + and its quieter builtin, a string and its muted docstring), so the palette + holds roughly fifteen to twenty swatches across few hues. The Shade budget + section counts them. + +3. *Spend salience deliberately.* Chroma, brightness, and bold all say "look + here"; muted and low-chroma say "supporting structure." Reserve the loudest + treatment for the few things that matter, and make the anchor (a definition, + the active element) louder than the echo (a use, the idle element). + +4. *Two channels: foreground is identity, background is state.* Foreground + carries what a thing is (its role). A background tint carries transient state: + selection, current line, search match, diff hunk. Do not recolor a + foreground to show state. Tint behind the text so the token keeps its + meaning while highlighted. A transient match chip may invert; persistent state + must only tint. + +5. *Tier the contrast, and judge it honestly.* Comfortable contrast for content, + low contrast for idle structure, high contrast for alerts. Avoid pure black or + white grounds. They cause halation (light text on a dark ground blooms at the + glyph edges and smears the letterforms, worst for astigmatic eyes) and general + eye strain. Low contrast does not mean low distinguishability. If contrast is + soft, keep enough lightness/chroma separation between roles. Pick and judge + colors in a perceptual space, OKLCH or CIELAB, not HSL. (OKLCH is the + cylindrical lightness/chroma/hue form of the OKLab perceptual color space, + [[https://bottosson.github.io/posts/oklab/][Ottosson 2020]]; CIELAB is the CIE 1976 Lab color space; HSL is + hue/saturation/lightness, whose "lightness" is not perceptual.) Judge on the + real display in the real room, because contrast and chroma are relative to the + ground and the ambient light. + +6. *Encode redundantly; never rely on color alone.* Anything that matters (errors, + diffs, matches, done-states) pairs its color with weight, underline, + or shape, so it survives color blindness and a poor display. Around 8% of men + have red-green color-vision deficiency; keep the palette distinguishable + without the color, and never let red-versus-green be the only signal. + +7. *Honor convention for the signal layer.* Red means error or deletion, green + means success or addition, amber means warning or modified, blue means + information or a link. Keep these consistent and, where you can, out of the + syntax accent pool, so a signal never reads as just another keyword. + +* Roles and the seed table + +The principles color a fixed set of reader-roles. Most are familiar from code, +but three of them (heading ramp, transient state, and signal) appear once you +look past syntax to UI and document faces. Every face in every tier classifies +into one of these roles; seeding a tier is classifying its faces and applying the +table. + +| Role | Palette family | Weight / shape | Channel | +|-----------------------------------------------------+-------------------------------------+-------------------+---------------------| +| Base / identity (default text, variables) | foreground | normal | fg | +| Structure (punctuation, operators, delimiters) | muted foreground | normal | fg | +| Control (keywords, preprocessor) | primary cool accent | bold, sparingly | fg | +| Builtins | control hue, lower chroma/lightness | normal | fg | +| Names: definitions | warm anchor accent | bold | fg | +| Names: uses / calls | same hue, quieter | normal | fg | +| Types / metadata / decorators | secondary accent | normal | fg | +| Strings / docstrings | green family | docstrings italic | fg | +| Escapes / regexps | brighter / teal green | normal | fg | +| Numbers / constants | warm literal accent | normal | fg | +| Comments | low-contrast lane | italic | fg | +| Heading ramp | one hue, lightness descending | level 1 strongest | fg | +| Transient state (region, current line, match, hunk) | quiet tint | none | bg | +| Signal: error / deletion | red | + weight/shape | fg, or bg for hunks | +| Signal: success / addition | green | none | fg / bg | +| Signal: warning / modified | amber | none | fg / bg | +| Signal: info / link | blue | underline | fg | + +This table is the guide made executable. The three tiers below are it, projected +onto three face inventories. + +** Shade budget + +The sharing rules fix how many shades each hue family needs and what each is for. +This is the swatch count a palette has to provide, and what =dupre= is built to: + +- *Neutrals (~5):* background, dim background, default foreground, muted + foreground (punctuation and operators), comment. +- *Cool accent, blue (2):* keyword, and builtin (the same hue at lower + chroma/lightness). +- *Warm anchor, gold (2):* definition (the strong anchor), and call (quieter, + same hue). +- *Secondary accent, violet (1):* types and decorators. +- *Green family (3):* string, docstring (muted), escape (brighter). +- *Teal (1):* regexp. +- *Warm literal, terracotta (1):* numbers and constants. +- *Signal (4):* error red, warning amber, success green, info/link blue, kept + out of the syntax accents where the palette can afford it (principle 7). +- *Heading ramp:* one hue across three or four lightness steps; document tiers + reuse an accent rather than spend a new hue. + +That is roughly fifteen swatches across seven or eight hues: few colors, each +doing related work by shade. The exact hex values live in the seeding-engine +spec; this section fixes the counts and the uses. + +* Syntax tier + +The syntax tier colors font-lock / tree-sitter categories. These are the roles +in the table, grouped the way a reader meets them. + +** Usual grouping + +Use these as starting groups: + +- *Base text:* foreground/default text, variable/use. +- *Structure:* punctuation, operators, comment delimiters. +- *Control / language syntax:* keywords, preprocessor forms, builtins. +- *Names / definitions:* function definitions, function calls, properties/fields. +- *Types / metadata:* types/classes, decorators, sometimes constants. +- *Literals:* strings, docstrings, regexps, escapes, numbers. +- *Comments:* comments and comment delimiters. + +** Sharing rules + +- Variables should usually look like normal text. If every variable is colored, + the buffer gets noisy quickly. +- Definitions should stand out more than uses. A function definition can be + brighter or bold while a function call stays in the same hue family but + quieter. +- Function calls and definitions can share hue. Use weight or brightness to mark + the definition as the stronger anchor. +- Types/classes and decorators often share a color because both describe shape, + annotation, or metadata rather than ordinary runtime values. +- Strings, docstrings, regexps, and escapes should be related but not identical. + Example: strings green, docstrings muted green, escapes brighter green, regexps + teal. +- Comments get their own low-contrast lane. Comment delimiters can be dimmer + than comment text. +- Punctuation and operators should be quiet. Usually use a muted foreground, + not a strong accent. +- Constants and numbers can share a warm literal color. If the palette is small, + constants can also share with types. +- Preprocessor forms can share with keywords unless they need to feel more + infrastructural; then make them slightly muted. +- Builtins should sit between keywords and normal identifiers: they should be + more noticeable than a user variable, but less commanding than syntax/control + keywords. In practice, use the keyword hue at lower chroma/lightness, or use + foreground with a subtle accent. + +** What "builtins between keywords and identifiers" means + +Keywords are language structure: =if=, =defun=, =class=, =return=, =let=. +They guide control flow and code shape, so they can carry a strong syntax color. + +Normal identifiers are user-authored names: local variables, arguments, ordinary +bindings. They are everywhere, so they should usually stay close to the default +foreground. + +Builtins are language-provided identifiers: =print=, =len=, =map=, +=Array.from=, =Promise=, =self=, =this=, standard macros, or core functions. +They are not syntax, but they are more meaningful than a random local variable. +"Between" means: + +- If keywords are blue and variables are foreground, builtins might be muted + blue-grey. +- If keywords are bold, builtins usually are not bold. +- If variables are plain foreground, builtins can be foreground plus a slight + hue shift. +- Builtins should be recognizable when scanning, but they should not dominate a + line the way control-flow keywords do. + +** Suggested compact mapping + +This is the canonical syntax mapping. It is what the bundled =dupre= theme should +seed to (note: dupre historically diverged, builtins on blue rather than +blue-grey and function definitions on silver rather than gold, and is being +reseeded to match this mapping). + +- *Foreground:* default text, variables. +- *Muted foreground:* punctuation, operators, comment delimiters. +- *Comment:* comments, disabled text. +- *Blue:* keywords, preprocessor. +- *Blue-grey:* builtins. +- *Gold:* function definitions and calls, with definitions stronger. +- *Violet:* types, classes, decorators. +- *Green:* strings, docstrings. +- *Teal / brighter green:* escapes, regexps. +- *Terracotta / warm accent:* numbers, constants, special literals. + +* UI faces tier + +UI faces carry almost no identity: they are the state, structure, and signal +layers of the table. So principles 4 (channels), 3 (active louder than idle), 7 +(convention), 5 (tiering), and 6 (redundancy) do nearly all the work, and they +draw their colors from the same palette (principle 2), never new ones. + +- *State is a background tint* (principle 4): =region=, =hl-line=, =highlight=, + =show-paren-match= tint behind syntax-colored text and set no foreground. + =isearch= may invert to a chip because a match marker is transient; persistent + state never does. +- *Active louder than idle* (principle 3): =mode-line= brighter than + =mode-line-inactive=; =line-number-current-line= accented against a dim + =line-number=; =isearch= (current match) louder than =lazy-highlight= (other + matches). Make the active and inactive mode-line clearly different: it is the + highest-traffic element and the cue for which window has focus. +- *Signals by convention* (principle 7): =error= red, =warning= amber, =success= + green, =isearch-fail= and =show-paren-mismatch= red. These are the semantic + layer, drawn from the palette's warm/cool accents. +- *Chrome recedes* (principle 5): =fringe= near the background, + =vertical-border= barely there, idle line numbers dim. Interactive and alert + faces get real contrast; structural chrome does not compete. +- *Redundant encoding* (principle 6): =link= is blue and underlined; + =show-paren-mismatch= uses a background plus shape, not color alone. + +The current dupre UI map already follows this, which is the point: it is a +seedable default, not a per-face tuning job. + +* Package faces tier: org-mode + +A package has many faces but few roles. org-mode (~88 faces) collapses into about +six, each driven by a principle. The long tail of other packages seeds to the +default foreground until any one earns the same treatment; org is worth doing +because it is a daily buffer. + +- *Heading ramp*: =org-level-1= through =org-level-8=. The textbook case for + principles 2 and 3: one hue family, level 1 the strongest (bright or bold), + each deeper level quieter. A lightness ramp in a single hue. Highest-value seed + in org, since headings dominate the view. +- *Markup that recedes*: =org-meta-line=, =org-drawer=, =org-special-keyword=, + =org-property-value=, =org-block-begin-line= / =org-block-end-line=, + =org-ellipsis=, =org-tag=, =org-date=, =org-document-info-keyword=. These are + org's punctuation and comments: the muted lane (principle 3 recede). +- *Code-like content reuses the syntax palette*: =org-block=, =org-code=, + =org-verbatim=, =org-inline-src-block=. Principle 1 at its clearest: a source + block is code, so it looks like code (the literal lane, the same accents as the + syntax tier). +- *State by convention*: =org-todo= and imminent deadlines read warm/red + (attention); =org-upcoming-deadline= amber; =org-scheduled= and =org-done= + recede to muted/cool, with =org-done= taking strikethrough or dim-italic so it + is not color-alone (principles 7, 3, 6). The agenda's deadline/scheduled/done + faces map straight onto the signal colors. +- *Links*: =org-link= is the link role: the same blue plus underline as the UI + link (principles 2, 6, 7). +- *Emphasis and quotes*: =org-quote=, =org-verse=, and doc-like text take + italic, the documentation lane (weight and slant below), kept readable. + +* Weight and slant + +- Use bold sparingly. Good targets: keywords, function definitions, TODO/error + states, important headings, or active/current UI elements. +- Avoid bolding every function call. It makes code visually lumpy and reduces + the value of bold for definitions and warnings. +- Italic works well for comments, docstrings, documentation-like text, and + sometimes parameters or decorators. Use it only if your chosen font has a + readable italic. +- Avoid italic for core control-flow keywords unless the theme is deliberately + stylized. Italic keywords can look decorative rather than structural. +- Keep bold and high chroma separate most of the time. A token that is both + bright and bold will dominate the buffer. + +* Contrast, chroma, and palette discipline + +- Keep default foreground/background comfortable first. Everything else depends + on the ground. +- Use high contrast for ordinary text and important UI states; use lower contrast + for comments, delimiters, and inactive UI. +- Avoid making comments so dim that they disappear. Comments are secondary, not + garbage. +- Use chroma to express semantic salience. More chroma means "look here"; lower + chroma means "supporting structure." +- Keep related roles in the same hue family and separate them by lightness, + chroma, or weight. +- Reserve the brightest accent for one or two roles. Common choices: function + definitions, strings, or keywords. +- Avoid assigning adjacent categories highly saturated unrelated hues. It makes + code look like a diagnostic heatmap. +- Use warm/cool balance deliberately. Warm colors advance visually; cool colors + recede. Put warm colors on rare, meaningful tokens if you want them noticed. +- Reuse hues across language families. A function definition should feel like a + function definition in Lisp, Python, JavaScript, and shell. + +* Signal colors and convention + +Principle 7 leans on conventions a reader already holds, and those conventions +are well-grounded. Not in what colors make us feel: the affective color-emotion +research is weak (brightness and saturation carry most of the effect, not hue), +culturally variable, and aimed at mood and branding rather than glyphs on a +ground. The grounding is in learned signal standards and in how the eye is +drawn. Red-stop and green-go trace to railway and traffic signaling and are +codified in the safety-color standards (ISO 3864, ANSI Z535); the pull of a +saturated color in a quiet field is pre-attentive (Treisman and Gelade 1980; +Ware, /Information Visualization/). + +| Signal | Conventional meaning | Where it shows | Basis | +|------------+-------------------------------+---------------------------------------------------+------------------------------------| +| Red | error, deletion, danger, stop | error, diff-removed, isearch-fail, paren-mismatch | traffic/rail stop; ISO 3864 danger | +| Amber | warning, caution, modified | warning, modified version-control state | ISO 3864 caution | +| Green | success, addition, ok, go | success, diff-added | traffic go; ISO 3864 safe | +| Blue | information, link, navigable | link, info messages | web-link convention; cool recedes | +| Muted grey | disabled, inactive, secondary | comments, inactive mode-line, dimmed text | low salience by design | + +Keep these consistent across the syntax, UI, and package tiers, and out of the +syntax accent pool where the palette can afford it, so a signal never reads as +just another token. This is a convention table, not an emotion table: it records +what a color has come to mean by use, which is what a reader actually decodes. + +* Accessibility and color vision + +- Run the palette through a color-blindness simulator before trusting it. Check + deuteranopia and protanopia (the common green-weak and red-weak deficiencies), + not just the urgent states. +- Blue and yellow stay distinct for nearly everyone; red and green are the risky + pair. When two roles must be told apart at a glance, prefer a blue/yellow or a + light/dark separation over a red/green one. +- For anything that must not be missed (diffs, errors, search hits, region), + pair the color with weight, underline, or shape, so the meaning survives + without it (principle 6). + +* Practical checks + +- Open real code in at least three languages before judging the palette. +- Squint at a buffer (or blur it): definitions, control flow, literals, and + comments should form distinct layers. If they don't, the palette is too flat or + too noisy. +- Check long files, not just curated snippets. Noise shows up in dense code. +- Check inactive windows, search highlights, region, diff, completions, and + diagnostics; syntax colors are only one part of a usable theme. +- If everything feels important, reduce chroma, remove bold, or merge colors. +- If nothing is scannable, increase separation between the main groups before + adding more hues. + +* Emacs specifics + +The rules above are general. In Emacs they land on concrete faces and a few +platform realities. + +** Theme the foundation faces first, inherit the rest + +- Map the syntax roles onto Emacs's canonical font-lock faces: + =font-lock-keyword-face=, =font-lock-function-name-face=, + =font-lock-variable-name-face=, =font-lock-type-face=, + =font-lock-constant-face=, =font-lock-builtin-face=, =font-lock-string-face=, + =font-lock-doc-face=, =font-lock-comment-face=, + =font-lock-comment-delimiter-face=, =font-lock-preprocessor-face=, and + =font-lock-warning-face=. +- Style those base faces well and let package faces inherit them. Most packages + declare faces that already =:inherit= a sensible base, so a good foundation + themes the long tail for free. Theme the base; do not chase every package. + +** Tree-sitter gives the finer faces this guide wants + +- Emacs 29's tree-sitter font-lock added the distinctions this guide asks for as + real faces. =font-lock-function-call-face= versus =font-lock-function-name-face= + is exactly "definitions stronger than calls"; there are also + =font-lock-variable-use-face=, =font-lock-property-use-face=, + =font-lock-property-name-face=, =font-lock-operator-face=, + =font-lock-bracket-face=, =font-lock-delimiter-face=, =font-lock-number-face=, + =font-lock-escape-face=, and =font-lock-regexp-face=. +- This is where "escapes brighter than strings, regexps teal" and "definitions + bolder than calls" become directly expressible. Note =treesit-font-lock-level= + controls how many of these levels actually fontify (default 3); some faces only + apply at higher levels. + +** Never leave the interface faces at their defaults + +- A usable theme is more than syntax. Always style =region=, =hl-line=, + =highlight=, =isearch= / =lazy-highlight= / =isearch-fail=, + =show-paren-match= / =show-paren-mismatch=, =cursor=, =mode-line= / + =mode-line-inactive=, =fringe=, =vertical-border=, =line-number= / + =line-number-current-line=, =minibuffer-prompt=, =link=, and =error= / + =warning= / =success=. + +** Handle terminal Emacs + +- The GUI is truecolor; =emacs -nw= may have only 256, 16, or 8 colors. Either + write display-class specs (a =((class color) (min-colors 256) ...)= clause with + a =(t ...)= fallback) or decide the theme is GUI-first and say so. +- Either way, define the 16 ANSI colors (ANSI is the terminal's standard set) + coherently with the palette: terminals, =ansi-color= in shells, and + compilation buffers all draw from them. + +** Build-and-audit tooling + +- =describe-face= (or =C-u C-x ==) at point tells you which face you are actually + looking at. It is the fastest way to find what to change. +- =M-x list-faces-display= shows every face in one buffer for a whole-theme audit. +- Test the daily buffers, not just code samples: org, magit (its diffs exercise + the semantic colors hard), dired, the completion popup (corfu / vertico / + company), and flymake/flycheck diagnostics. + +* Using this with theme-studio + +This guide is the design philosophy behind the theme-studio in this directory. +The tool is where the rules get applied, by eye and increasingly by metric. + +- *Worked example:* the bundled =dupre= theme is built from a palette of these + role-colors (blue, gold, regal/violet, sage/green, terracotta, plus neutral + silvers). Its role-to-color bindings live in =dupre.json= under =assignments=; + read it next to the seed table and the compact mapping above. (dupre is being + reseeded to match the compact mapping exactly; see the Syntax tier note.) +- *Checking contrast and palette discipline:* the tool's readouts verify by + number what this guide states as principle. Today that is the AA/AAA contrast + mask (the 4.5:1 and 7:1 tiers from WCAG, the Web Content Accessibility + Guidelines, [[https://www.w3.org/TR/WCAG21/][w3.org/TR/WCAG21]]). The planned OKLCH, APCA (Accessible Perceptual + Contrast Algorithm, [[https://github.com/Myndex/apca-w3][Myndex]]), and pairwise ΔE (perceptual color-difference) + diagnostics make "use chroma to express salience" and "low contrast does not + mean low distinguishability" checkable instead of eyeballed. See + [[file:../../docs/design/theme-studio-perceptual-color-metrics-spec.org][docs/design/theme-studio-perceptual-color-metrics-spec.org]]. +- *Seeding:* the seed table is the contract the tool seeds from: syntax, UI, and + org tiers each start from guide-correct defaults, leaving you to retune hues + rather than build a theme from blank. +- *Shipping a palette:* =build-theme.el= converts a =theme.json= exported from + the tool into a loadable Emacs deftheme, so a palette designed under these + rules becomes a real theme. + +* Sources and further reading + +Contrast, color space, and accessibility: + +- WCAG 2.1, especially SC 1.4.3 Contrast (Minimum) and SC 1.4.1 Use of Color: + [[https://www.w3.org/TR/WCAG21/][w3.org/TR/WCAG21]]. The baseline contrast model and the canonical "never rely + on color alone" rule. +- WCAG 3.0 Working Draft: [[https://www.w3.org/TR/wcag-3.0/][w3.org/TR/wcag-3.0]]. Still a draft and years from + final; its contrast method is undetermined, so treat it as direction, not law. +- APCA (Accessible Perceptual Contrast Algorithm), Myndex: + [[https://github.com/Myndex/apca-w3][github.com/Myndex/apca-w3]] and [[https://apcacontrast.com/][apcacontrast.com]]. The polarity-aware perceptual + contrast model, more trustworthy than WCAG 2 in the low-contrast band. +- Björn Ottosson, "A perceptual color space for image processing" (OKLab, 2020): + [[https://bottosson.github.io/posts/oklab/][bottosson.github.io/posts/oklab]]. Why OKLCH, with the conversion math. +- Sharma, Wu & Dalal, "The CIEDE2000 Color-Difference Formula" (2005). The + perceptual color-difference standard that ΔE-OK approximates more cheaply. + +Emacs faces and theming: + +- Elisp manual: [[info:elisp#Faces][(elisp) Faces]], [[info:elisp#Faces for Font Lock][(elisp) Faces for Font Lock]], and + [[info:elisp#Display Feature Testing][(elisp) Display Feature Testing]] (the display-class / =min-colors= specs for + terminal fallback). +- Emacs manual: [[info:emacs#Standard Faces][(emacs) Standard Faces]] and [[info:emacs#Custom Themes][(emacs) Custom Themes]]. +- Tree-sitter font-lock faces and =treesit-font-lock-level= (Emacs 29+): the + Elisp manual's font-lock sections, and =M-x describe-variable treesit-font-lock-level=. +- Protesilaos Stavrou, Modus Themes: [[https://protesilaos.com/emacs/modus-themes][protesilaos.com/emacs/modus-themes]]. A + rigorously accessible Emacs theme with documented contrast rationale, and the + high-contrast counterpoint to the low-contrast school this guide leans toward. +- base16, Chris Kempson: [[https://github.com/chriskempson/base16][github.com/chriskempson/base16]]. A 16-color scheme + convention, useful for the terminal/ANSI palette mapping above. diff --git a/scripts/theme-studio/theme-studio.html b/scripts/theme-studio/theme-studio.html index 37be4128..8a5aca75 100644 --- a/scripts/theme-studio/theme-studio.html +++ b/scripts/theme-studio/theme-studio.html @@ -34,7 +34,9 @@ .svcur{position:absolute;width:16px;height:16px;border:2px solid #fff;border-radius:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #0008;pointer-events:none} .hue{position:relative;width:34px;height:320px;border-radius:4px;cursor:ns-resize;background:linear-gradient(to bottom,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)} .huecur{position:absolute;left:-2px;right:-2px;height:4px;background:#fff;border:1px solid #0008;transform:translateY(-50%);pointer-events:none} - .pinfo{display:flex;justify-content:space-between;margin:10px 2px 8px;font:12pt monospace;color:#cdced1} + .pinfo{display:flex;justify-content:space-between;margin:10px 2px 4px;font:12pt monospace;color:#cdced1} + .pinfo2{display:flex;justify-content:space-between;margin:0 2px 9px;font:10pt monospace;color:#9aa3ad} + .pinfo2 span{cursor:default} .pkchips{display:flex;flex-wrap:wrap;gap:5px} .pkchips .pc{width:28px;height:28px;border-radius:3px;border:1px solid #555;cursor:pointer} .palctl button,.filebar button,.fbtn{background:#252321;color:#e8bd30;border:1px solid #3a3a3a;border-radius:4px;padding:6px 12px;font:10pt monospace;cursor:pointer} #palmsg{font:10pt monospace;opacity:0;transition:opacity .35s;margin-left:6px} @@ -78,6 +80,7 @@ <div id="hue" class="hue"><div id="huecur" class="huecur"></div></div> </div> <div class="pinfo"><span id="pkhex">#888888</span><span id="pkcon"></span></div> + <div class="pinfo2"><span id="pkoklch" title="OKLCH perceptual coordinates: lightness L (0..1), chroma C, hue H in degrees"></span><span id="pkapca"></span></div> <div class="pmode">limit <button data-m="any" class="on">any</button><button data-m="aa">AA+</button><button data-m="aaa">AAA</button></div> <div id="pkchips" class="pkchips"></div> </div> @@ -142,11 +145,178 @@ function packagesForExport(map){const out={};for(const app in map){const faces={ function mergePackagesInto(map,pkgs){if(!pkgs)return;for(const app in pkgs){if(!map[app])map[app]={};for(const face in pkgs[app]){const f=pkgs[app][face]||{};map[app][face]={fg:f.fg??null,bg:f.bg??null,bold:!!f.bold,italic:!!f.italic,underline:!!f.underline,strike:!!f.strike,inherit:f.inherit??null,height:f.height||1,source:f.source||'user'};}}} let PKGMAP=seedPkgmap(); function esc(t){return t.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');} -function lin(c){c/=255;return c<=0.03928?c/12.92:Math.pow((c+0.055)/1.055,2.4);} -function rl(h){return 0.2126*lin(parseInt(h.substr(1,2),16))+0.7152*lin(parseInt(h.substr(3,2),16))+0.0722*lin(parseInt(h.substr(5,2),16));} +// Pure color-math core (lin/rl/contrast/rating/hsv2rgb/rgb2hsv/hex2rgb/rgb2hex, +// plus OKLab/OKLCH/APCA/deltaE), inlined verbatim from colormath.js. normHex, +// textOn, and ratingColor stay below as UI-boundary helpers. +// colormath.js — pure color-math core for theme-studio. +// +// One source of truth: node imports this module (tests); generate.py inlines its +// body into the page (stripping the trailing export block) so the browser runs +// the same code. No DOM, no side effects. +// +// Algorithms: OKLab/OKLCH from Bjorn Ottosson (2020, +// https://bottosson.github.io/posts/oklab/); APCA from APCA-W3 0.1.9 +// (https://github.com/Myndex/apca-w3); deltaE is OKLab Euclidean distance. + +function hex2rgb(h) { + return [parseInt(h.substr(1, 2), 16), parseInt(h.substr(3, 2), 16), parseInt(h.substr(5, 2), 16)]; +} + +// sRGB transfer (0..1 channel <-> linear-light). +function lin(c) { return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); } +function delin(c) { return c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055; } +function clamp01(c) { return c < 0 ? 0 : c > 1 ? 1 : c; } + +function srgb2oklab(hex) { + const [R, G, B] = hex2rgb(hex); + const r = lin(R / 255), g = lin(G / 255), b = lin(B / 255); + const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b; + const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b; + const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b; + const l_ = Math.cbrt(l), m_ = Math.cbrt(m), s_ = Math.cbrt(s); + return { + L: 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_, + a: 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_, + b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_, + }; +} + +function oklab2oklch(lab) { + let H = Math.atan2(lab.b, lab.a) * 180 / Math.PI; + if (H < 0) H += 360; + return { L: lab.L, C: Math.hypot(lab.a, lab.b), H }; +} + +function oklch2oklab(L, C, H) { + const hr = H * Math.PI / 180; + return { L, a: C * Math.cos(hr), b: C * Math.sin(hr) }; +} + +// OKLab -> linear sRGB (may fall outside [0,1] when out of gamut). +function oklab2lrgb(L, a, b) { + const l_ = L + 0.3963377774 * a + 0.2158037573 * b; + const m_ = L - 0.1055613458 * a - 0.0638541728 * b; + const s_ = L - 0.0894841775 * a - 1.2914855480 * b; + const l = l_ * l_ * l_, m = m_ * m_ * m_, s = s_ * s_ * s_; + return [ + 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s, + -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s, + -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s, + ]; +} + +function inGamut(lrgb) { + const e = 1e-4; + return lrgb.every(c => c >= -e && c <= 1 + e); +} + +function lrgb2hex(lrgb) { + return '#' + lrgb.map(c => { + const v = Math.round(clamp01(delin(clamp01(c))) * 255); + return v.toString(16).padStart(2, '0'); + }).join(''); +} + +// OKLCH -> in-gamut sRGB hex. When the requested chroma is unreachable, reduce C +// by binary search holding L and H fixed; report whether clamping happened. +function oklch2hex(L, C, H) { + const lab0 = oklch2oklab(L, C, H); + const lrgb0 = oklab2lrgb(lab0.L, lab0.a, lab0.b); + if (inGamut(lrgb0)) return { hex: lrgb2hex(lrgb0), clamped: false }; + let lo = 0, hi = C; + for (let i = 0; i < 24; i++) { + const mid = (lo + hi) / 2; + const lab = oklch2oklab(L, mid, H); + if (inGamut(oklab2lrgb(lab.L, lab.a, lab.b))) lo = mid; else hi = mid; + } + const lab = oklch2oklab(L, lo, H); + return { hex: lrgb2hex(oklab2lrgb(lab.L, lab.a, lab.b)), clamped: true }; +} + +// APCA-W3 0.1.9. Returns signed Lc: positive for dark-text-on-light, negative +// for light-text-on-dark. Constants transcribed verbatim from the pinned source. +function apcaY(hex) { + const [R, G, B] = hex2rgb(hex); + return 0.2126729 * Math.pow(R / 255, 2.4) + + 0.7151522 * Math.pow(G / 255, 2.4) + + 0.0721750 * Math.pow(B / 255, 2.4); +} + +function apca(textHex, bgHex) { + const blkThrs = 0.022, blkClmp = 1.414, deltaYmin = 0.0005; + const normBG = 0.56, normTXT = 0.57, revTXT = 0.62, revBG = 0.65; + const scaleBoW = 1.14, scaleWoB = 1.14, loBoWoffset = 0.027, loWoBoffset = 0.027, loClip = 0.1; + let Ytxt = apcaY(textHex), Ybg = apcaY(bgHex); + Ytxt = Ytxt > blkThrs ? Ytxt : Ytxt + Math.pow(blkThrs - Ytxt, blkClmp); + Ybg = Ybg > blkThrs ? Ybg : Ybg + Math.pow(blkThrs - Ybg, blkClmp); + if (Math.abs(Ybg - Ytxt) < deltaYmin) return 0; + let out; + if (Ybg > Ytxt) { + const sapc = (Math.pow(Ybg, normBG) - Math.pow(Ytxt, normTXT)) * scaleBoW; + out = sapc < loClip ? 0 : sapc - loBoWoffset; + } else { + const sapc = (Math.pow(Ybg, revBG) - Math.pow(Ytxt, revTXT)) * scaleWoB; + out = sapc > -loClip ? 0 : sapc + loWoBoffset; + } + return out * 100; +} + +// deltaE-OK: Euclidean distance in OKLab. +function deltaE(aHex, bHex) { + const x = srgb2oklab(aHex), y = srgb2oklab(bHex); + return Math.hypot(x.L - y.L, x.a - y.a, x.b - y.b); +} + +// --- WCAG 2.x relative luminance + contrast (migrated from the page inline) --- +// rl reuses the canonical lin() above. On 8-bit channels lin's 0.04045 cutoff is +// byte-identical to the WCAG 0.03928 piecewise the inline copy used — no channel +// value falls between the two thresholds (10/255 = 0.0392, 11/255 = 0.0431) — so +// every #rrggbb contrast value is preserved exactly. +function rl(hex) { + const [R, G, B] = hex2rgb(hex); + return 0.2126 * lin(R / 255) + 0.7152 * lin(G / 255) + 0.0722 * lin(B / 255); +} + +function contrast(aHex, bHex) { + const L1 = rl(aHex), L2 = rl(bHex), hi = Math.max(L1, L2), lo = Math.min(L1, L2); + return (hi + 0.05) / (lo + 0.05); +} + +function rating(r) { return r >= 7 ? 'AAA' : r >= 4.5 ? 'AA' : 'FAIL'; } + +// --- HSV <-> sRGB for the color picker (migrated from the page inline) --- +function hsv2rgb(h, s, v) { + h = (h % 360 + 360) % 360 / 360; + const i = Math.floor(h * 6), f = h * 6 - i, p = v * (1 - s), q = v * (1 - f * s), t = v * (1 - (1 - f) * s); + let r, g, b; + switch (((i % 6) + 6) % 6) { + case 0: [r, g, b] = [v, t, p]; break; + case 1: [r, g, b] = [q, v, p]; break; + case 2: [r, g, b] = [p, v, t]; break; + case 3: [r, g, b] = [p, q, v]; break; + case 4: [r, g, b] = [t, p, v]; break; + default: [r, g, b] = [v, p, q]; + } + return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; +} + +function rgb2hsv(r, g, b) { + r /= 255; g /= 255; b /= 255; + const mx = Math.max(r, g, b), mn = Math.min(r, g, b), d = mx - mn; + let h = 0; + if (d) { + if (mx === r) h = ((g - b) / d + 6) % 6; + else if (mx === g) h = (b - r) / d + 2; + else h = (r - g) / d + 4; + h *= 60; + } + return [h, mx ? d / mx : 0, mx]; +} + +function rgb2hex(r, g, b) { + return '#' + [r, g, b].map(x => Math.max(0, Math.min(255, x)).toString(16).padStart(2, '0')).join(''); +} function textOn(h){const L=rl(h);return ((L+0.05)/0.05)>(1.05/(L+0.05))?'#000':'#fff';} -function contrast(a,b){const L1=rl(a),L2=rl(b),hi=Math.max(L1,L2),lo=Math.min(L1,L2);return (hi+0.05)/(lo+0.05);} -function rating(r){return r>=7?'AAA':r>=4.5?'AA':'FAIL';} function ratingColor(r){return r>=7?'#5d9b86':r>=4.5?'#a9b2bb':'#cb6b4d';} function cid(l){return l.replace(/\W/g,'');} function buildLangSel(){const s=document.getElementById('langsel');s.innerHTML='';for(const lang in SAMPLES){const o=document.createElement('option');o.value=lang;o.textContent=lang;s.appendChild(o);}} @@ -232,21 +402,19 @@ function updateColor(){ } function normHex(s){s=s.trim();if(/^[0-9a-fA-F]{6}$/.test(s))s='#'+s;return /^#[0-9a-fA-F]{6}$/.test(s)?s.toLowerCase():null;} function curHex(){return normHex(document.getElementById('newhexstr').value)||'#888888';} -function hsv2rgb(h,s,v){h=(h%360+360)%360/360;const i=Math.floor(h*6),f=h*6-i,p=v*(1-s),q=v*(1-f*s),t=v*(1-(1-f)*s);let r,g,b;switch(((i%6)+6)%6){case 0:[r,g,b]=[v,t,p];break;case 1:[r,g,b]=[q,v,p];break;case 2:[r,g,b]=[p,v,t];break;case 3:[r,g,b]=[p,q,v];break;case 4:[r,g,b]=[t,p,v];break;default:[r,g,b]=[v,p,q];}return[Math.round(r*255),Math.round(g*255),Math.round(b*255)];} -function rgb2hsv(r,g,b){r/=255;g/=255;b/=255;const mx=Math.max(r,g,b),mn=Math.min(r,g,b),d=mx-mn;let h=0;if(d){if(mx===r)h=((g-b)/d+6)%6;else if(mx===g)h=(b-r)/d+2;else h=(r-g)/d+4;h*=60;}return[h,mx?d/mx:0,mx];} -function hex2rgb(h){return[parseInt(h.substr(1,2),16),parseInt(h.substr(3,2),16),parseInt(h.substr(5,2),16)];} -function rgb2hex(r,g,b){return '#'+[r,g,b].map(x=>Math.max(0,Math.min(255,x)).toString(16).padStart(2,'0')).join('');} let pkH=0,pkS=0,pkV=0.5,pickerOn=false; let pkMode='any'; function pkThresh(){return pkMode==='aa'?4.5:pkMode==='aaa'?7:0;} function drawMask(){const cv=document.getElementById('svmask');if(!cv)return;const sv=document.getElementById('sv'),w=cv.width=sv.clientWidth,h=cv.height=sv.clientHeight,ctx=cv.getContext('2d');ctx.clearRect(0,0,w,h);const T=pkThresh();if(!T)return;ctx.fillStyle='rgba(8,7,6,0.66)';const step=4;for(let x=0;x<w;x+=step){const S=x/w;for(let y=0;y<h;y+=step){const V=1-y/h,[r,g,b]=hsv2rgb(pkH,S,V);if(contrast(rgb2hex(r,g,b),MAP['bg'])<T)ctx.fillRect(x,y,step,step);}}} function paintPicker(){const sv=document.getElementById('sv');if(!sv)return;sv.style.background=`linear-gradient(to top,#000,rgba(0,0,0,0)),linear-gradient(to right,#fff,rgba(255,255,255,0)),hsl(${pkH},100%,50%)`;const w=sv.clientWidth,h=sv.clientHeight,hh=document.getElementById('hue').clientHeight;document.getElementById('svcur').style.left=(pkS*w)+'px';document.getElementById('svcur').style.top=((1-pkV)*h)+'px';document.getElementById('huecur').style.top=((pkH/360)*hh)+'px';drawMask();} -function pkReadout(h){const e=document.getElementById('pkhex');if(e)e.textContent=h;const c=document.getElementById('pkcon');if(c){const r=contrast(h,MAP['bg']);c.textContent=r.toFixed(1)+' '+rating(r);c.style.color=ratingColor(r);}} +function pkReadout(h){const e=document.getElementById('pkhex');if(e)e.textContent=h;const c=document.getElementById('pkcon');if(c){const r=contrast(h,MAP['bg']);c.textContent=r.toFixed(1)+' '+rating(r);c.style.color=ratingColor(r);} + const o=document.getElementById('pkoklch');if(o){const lch=oklab2oklch(srgb2oklab(h));o.textContent='OKLCH '+lch.L.toFixed(3)+' '+lch.C.toFixed(3)+' '+Math.round(lch.H)+'\u00b0';} + const a=document.getElementById('pkapca');if(a){const lc=apca(h,MAP['bg']);a.textContent='APCA Lc '+lc.toFixed(0);a.title='APCA Lc '+lc.toFixed(1)+' (APCA-W3 0.1.9), text on the ground color. Positive = dark text on a light background, negative = light text on a dark background.';}} function syncHex(){const v=normHex(document.getElementById('newhexstr').value);if(!v)return;document.getElementById('swatch').style.background=v;[pkH,pkS,pkV]=rgb2hsv(...hex2rgb(v));if(pickerOn)paintPicker();pkReadout(v);} function setHex(h){h=normHex(h)||h;document.getElementById('newhexstr').value=h;document.getElementById('swatch').style.background=h;[pkH,pkS,pkV]=rgb2hsv(...hex2rgb(h));if(pickerOn)paintPicker();pkReadout(h);} function pkSet(){const hex=rgb2hex(...hsv2rgb(pkH,pkS,pkV));document.getElementById('newhexstr').value=hex;document.getElementById('swatch').style.background=hex;paintPicker();pkReadout(hex);} function buildPkChips(){const c=document.getElementById('pkchips');if(!c)return;c.innerHTML='';const T=pkThresh();PALETTE.forEach(([hex,name])=>{const s=document.createElement('div');s.className='pc';s.style.background=hex;s.title=name+' '+hex;const ok=!T||contrast(hex,MAP['bg'])>=T;if(!ok){s.style.opacity='0.22';s.title+=' (below '+pkMode.toUpperCase()+')';}s.onclick=()=>{if(ok)setHex(hex);};c.appendChild(s);});} -function openPicker(){pickerOn=true;[pkH,pkS,pkV]=rgb2hsv(...hex2rgb(curHex()));buildPkChips();paintPicker();pkReadout(curHex());document.getElementById('picker').style.display='block';setTimeout(()=>document.addEventListener('pointerdown',pkOutside),0);} +function openPicker(){pickerOn=true;[pkH,pkS,pkV]=rgb2hsv(...hex2rgb(curHex()));buildPkChips();document.getElementById('picker').style.display='block';paintPicker();pkReadout(curHex());setTimeout(()=>document.addEventListener('pointerdown',pkOutside),0);} function closePicker(){if(!pickerOn)return;pickerOn=false;const p=document.getElementById('picker');if(p)p.style.display='none';document.removeEventListener('pointerdown',pkOutside);} function pkOutside(e){if(!e.target.closest('#picker')&&!e.target.closest('#swatch'))closePicker();} function pkDrag(el,fn){el.addEventListener('pointerdown',e=>{e.preventDefault();fn(e);const mv=ev=>fn(ev),up=()=>{document.removeEventListener('pointermove',mv);document.removeEventListener('pointerup',up);};document.addEventListener('pointermove',mv);document.addEventListener('pointerup',up);});} @@ -737,5 +905,16 @@ function pkgSelftest(){ } if(location.hash==='#selftest')pkgSelftest(); if(location.hash.startsWith('#pick')){openPicker();const m=location.hash.slice(5);if(m){const b=document.querySelector('.pmode button[data-m="'+m+'"]');if(b)b.click();}} +if(location.hash==='#cursortest'){document.getElementById('newhexstr').value='#67809c';openPicker();const sc=document.getElementById('svcur'),hc=document.getElementById('huecur');const L=parseFloat(sc.style.left||'0'),T=parseFloat(sc.style.top||'0'),H=parseFloat(hc.style.top||'0');const ok=L>1&&T>1&&H>1;document.title='CURSORTEST '+(ok?'PASS':'FAIL');const d=document.createElement('div');d.id='cursortest';d.textContent='CURSORTEST '+(ok?'PASS':'FAIL')+' left='+sc.style.left+' top='+sc.style.top+' hue='+hc.style.top;document.body.appendChild(d);} if(location.hash.startsWith('#app')){const ap=location.hash.slice(4),s=document.getElementById('appsel');if(s&&ap){s.value=ap;pkgChanged();}} +if(location.hash==='#readouttest'){const hex='#67809c';document.getElementById('newhexstr').value=hex;openPicker();pkReadout(hex); + const o=document.getElementById('pkoklch').textContent,a=document.getElementById('pkapca').textContent,w=document.getElementById('pkcon').textContent; + const lch=oklab2oklch(srgb2oklab(hex)); + const expO='OKLCH '+lch.L.toFixed(3)+' '+lch.C.toFixed(3)+' '+Math.round(lch.H)+'\u00b0'; + const expA='APCA Lc '+apca(hex,MAP['bg']).toFixed(0); + const r=contrast(hex,MAP['bg']),expW=r.toFixed(1)+' '+rating(r); + const wired=o===expO&&a===expA&&w===expW; + const sane=Math.abs(lch.L-0.591)<0.01&&Math.abs(lch.C-0.052)<0.01&&Math.abs(lch.H-251.6)<2; + const ok=wired&&sane;document.title='READOUTTEST '+(ok?'PASS':'FAIL'); + const d=document.createElement('div');d.id='readouttest';d.textContent='READOUTTEST '+(ok?'PASS':'FAIL')+' oklch='+o+' | apca='+a+' | wcag='+w;document.body.appendChild(d);} </script>
\ No newline at end of file @@ -118,6 +118,20 @@ Rewrote =README.md= for the full tool: three face tiers + palette, the in-page p *** 2026-06-08 Mon @ 02:40:00 -0500 theme-studio tier 3 — test surface landed Extended the guarded =#selftest= harness (headless Chrome) to assert the acceptance criteria against the real emitted code: old-JSON import (no =packages=), full round-trip (fg/bg/bold/italic/inherit/height/source), cleared-state export, unknown-package/face preservation, and inheritance-cycle termination — all PASS. The two DOM-coupled regressions are handled structurally: =updateColor= remaps =PKGMAP= on a palette-color edit, and =PKGMAP= stores hexes so a deleted palette color leaves package refs in the "(gone)" recoverable state. =generate.py= rebuilds =theme-studio.html= each run. +** TODO [#B] theme-studio perceptual color metrics :feature:theme:theme-studio: +Spec (Ready, opens confirmed 2026-06-08): [[file:docs/design/theme-studio-perceptual-color-metrics-spec.org][docs/design/theme-studio-perceptual-color-metrics-spec.org]]. OKLCH model + perceptual-L/APCA readouts + pairwise ΔE, for building low-contrast themes by metric rather than by eye. Phases run in dependency order; the math core extracts to a Node-unit-tested =colormath.js= and the browser hash tests verify UI wiring. vNext deferrals (low-contrast preset, CIEDE2000) are the two [#D] tasks below. +*** 2026-06-08 Mon @ 19:43:50 -0500 Color-math foundation + Node tests landed +Pure color core in =scripts/theme-studio/colormath.js= (OKLab/OKLCH, APCA-W3 0.1.9 exact constants, ΔE-OK, binary-search gamut clamp returning ={hex,clamped}=) shipped in 49342bf5; this phase finished the integration in 78260018. =generate.py= now inlines the colormath.js body into the page script (export-stripped, =COLORMATH_J= placeholder), and the page's lin/rl/contrast/rating/hsv2rgb/rgb2hsv/hex2rgb/rgb2hex copies moved into the module — =rl= reuses the canonical =lin= (0.04045 cutoff), byte-identical to the old 0.03928 form on every #rrggbb (no 8-bit channel falls between the cutoffs; verified over 200k pairs, zero contrast change). =test-colormath.mjs= gained Normal/Boundary/Error cases for the migrated helpers, a seeded hsv-rgb round-trip property test, and an inline-integrity check that the generated page carries the module body verbatim. Gate met: =node --test scripts/theme-studio/*.mjs= 15 pass, colormath.js 100% line / 93.75% branch / 100% func; =node --check= on the spliced script clean; =#selftest= + =#cursortest= PASS in headless Chrome. NOTE: =node --test <dir>= directory-globbing is broken on Node v26 (tries to load the dir as a module) — use the =*.mjs= glob form. +*** 2026-06-08 Mon @ 19:55:53 -0500 Picker OKLCH/APCA readouts landed +Phase 2 shipped in 77c7f126. Second readout row (=.pinfo2=) under the WCAG ratio: OKLCH L/C/H + signed APCA Lc against the ground color, always shown; sign convention in the APCA tooltip + README. Tables unchanged (APCA picker-only per Agreed-decision #3). =pkReadout= drives the spans from the inlined colormath functions. Gate met: =#readouttest= asserts the spans match the live computation AND the known dupre-blue OKLCH reference (L 0.591 / C 0.052 / H 252°, APCA Lc -34 on ground) with WCAG unchanged; =#selftest= + =#cursortest= still PASS; 15 Node tests green. Headless-rendered values verified against a node cross-check. Visual eyeball is the open "Perceptual readouts read well in the picker" item under Manual testing. +*** TODO [#B] Palette ΔE warnings :solo: +Phase 3. Pairwise ΔE-OK across =PALETTE=; warn on pairs below 0.02 (named constant), sorted closest-first, capped at 5 with "and N more"; nearest-neighbor ΔE in each chip title. Gate: =#deltatest= PASS. +*** TODO [#B] OKLCH sliders + color-model control :solo: +Phase 4a. Separate =pkModel= (HSV/OKLCH) from =pkMode= (AA/AAA mask); OKLCH L/C/H numeric + range inputs driving =oklch2hex=; clamp status text. HSV stays default. Gate: =#oklchtest= (model/mask independence + color preserved across switch) PASS. +*** TODO [#B] Chroma×Lightness plane :solo: +Phase 4b. Render the SV box as a C×L plane at fixed hue in OKLCH mode; gamut-mask the out-of-range region (reuse the =drawMask()= pattern); cache on (hue + dims + mask + bg hex); defer redraw until pointer settles. Gate: the 4b plane hash test (crosshair lands at the color's C/L; a known out-of-gamut coordinate is masked). +*** TODO [#B] Test surface green :solo:tests: +Keep the Node unit tests (+coverage), the UI hash tests (=#cursortest=/=#readouttest=/=#deltatest=/=#oklchtest=/4b), =#selftest=, the inline-integrity check, =node --check=, and the README/doc updates green across the feature. ** TODO Manual testing and validation :verify:theme-studio: Exercised once the phases above land. *** TODO Seeded package-face defaults look right @@ -132,6 +146,41 @@ What we're verifying: org's ~88-face and magit's ~111-face tables stay navigable - Type "agenda" in the filter - Reassign one face and watch the preview Expected: rows are grouped, the filter narrows them, and a reassignment updates the preview live. +*** TODO Perceptual readouts read well in the picker +What we're verifying: the OKLCH L/C/H and APCA Lc readouts are legible and correctly placed beside the WCAG number. +- Open =scripts/theme-studio/theme-studio.html= in Chrome and open the picker on a few colors +- Read the OKLCH and APCA values against the WCAG ratio +Expected: the new readouts are clear, the APCA sign/polarity is understandable, and nothing crowds the readout bar. +*** TODO ΔE warnings read clearly +What we're verifying: the too-similar-pair warning is legible and the cap behaves. +- Build a palette with two near-identical colors, then a well-spread one +- Read the warning line each time +Expected: the close pair is named with its ΔE, sorted closest-first, capped at 5 with "and N more"; the well-spread palette shows no warning. +*** TODO OKLCH editor feels right +What we're verifying: the OKLCH sliders / C×L plane edit cleanly and clamping is visible. +- Switch the picker to OKLCH mode and drag L, then C, then H +- Push chroma past the sRGB gamut, then toggle the AA/AAA mask +Expected: each axis moves independently; the C×L plane (once 4b lands) opens on the current color; "chroma clamped to sRGB" shows on clamp; toggling the mask does not reset OKLCH mode. +** TODO [#B] theme-studio guide-support features :feature:theme-studio: +From the color-assignment guide work (2026-06-08): make the tool support the guide without mandating it — everything a seed, an advisory, or a view, never a gate. Two specs to write, both deriving from the rewritten guide and its seed table ([[file:scripts/theme-studio/theme-coloring-guide.org][theme-coloring-guide.org]]). +*** 2026-06-08 Mon @ 19:08:00 -0500 Seeding-engine spec written and Ready +[[file:docs/design/theme-studio-seeding-engine-spec.org][theme-studio-seeding-engine-spec.org]] — role table + face→role maps for syntax/UI/org, OKLCH shade generation, reseed dupre-revised to the compact mapping. Codex-reviewed, Ready. Implementation tracked under the seeding-engine parent below. +*** TODO Guide-support views and advisories spec :solo: +Five optional surfaces, all dismissible and non-blocking, in one collapsible panel where they advise: (1) CVD-simulation toggle on previews (deuteranopia/protanopia/tritanopia); (2) squint/blur preview toggle; (3) lightness-ramp view + palette advisories (accent count over 6-8, roles separated only by red/green) — depends on the OKLCH/ΔE core; (4) definition-vs-call / weight advisories; (5) state-over-syntax preview (region/search/diff tint over real syntax-colored text). Sequence: rewritten guide reviewed → seeding-engine spec → this. Advisories (3, 4) layer on the perceptual-metrics feature. +** TODO [#B] theme-studio seeding engine :feature:theme:theme-studio: +Spec (Ready): [[file:docs/design/theme-studio-seeding-engine-spec.org][spec]]. Role table → guide-correct defaults for syntax/UI/org; reseed dupre-revised.json to the compact mapping; opens seeded with an all-tier reseed button. Depends on the perceptual-metrics colormath.js core for OKLCH shade generation, so it runs after that feature's Phase 1. +*** TODO Seed model + seed() + #seedtest :solo: +Phase 1. Palette anchors + OKLCH shade generation (reusing colormath.js), the ROLES table, and the three face→role maps as data; pure seed(). Gate: #seedtest asserts representative syntax/UI/org faces resolve correctly (bi→blue-grey, fnd→gold+bold, region bg-only, link underlined, org-level-1 strongest, org-code literal lane) and a non-org bespoke package (magit) keeps its curated seed. +*** TODO Open-seeded + reseed + dupre-revised regen :solo: +Phase 2. Initial state from seed() plus seedPkgmap for the non-org packages; all-tier reseed button with a scope-named overwrite warning, resetting non-org to their APPS defaults; regenerate dupre-revised.json. Gate: #selftest PASS; default-on-open equals seed(); artifact round-trip (regenerated dupre-revised.json imports back to the same seeded state); Chrome eyeball. +*** TODO Seeding-engine test surface :solo:tests: +Keep #seedtest, #selftest, the default-on-open check, the dupre-revised round-trip, node --check, and Chrome validation green. +** TODO [#D] theme-studio per-tier reseed controls :feature:theme-studio: +Deferred from the seeding-engine spec (vNext). V1 reseeds all three guide-owned tiers at once; later consider separate "reseed syntax", "reseed UI", and "reseed package/org" controls if all-at-once proves too blunt. Spec: [[file:docs/design/theme-studio-seeding-engine-spec.org][spec]] (vNext; review folded in 2026-06-08). +** TODO [#D] theme-studio low-contrast preset/mask mode :feature:theme-studio: +Deferred from the perceptual color metrics spec (vNext). After raw OKLCH/APCA/DeltaE readouts exist, decide whether to add a named low-contrast workflow: APCA Lc bands, a contrast ceiling/floor mask, or a "soft" sibling to the existing any/AA+/AAA picker mask. Spec: [[file:docs/design/theme-studio-perceptual-color-metrics-spec.org][spec]] (vNext candidates; review folded in 2026-06-08). +** TODO [#D] theme-studio CIEDE2000 DeltaE option :feature:theme-studio: +Deferred from the perceptual color metrics spec (vNext). v1 uses DeltaE-OK on its native scale with a 0.02 threshold (decided); revisit CIEDE2000 only if the native OKLab scale proves too unfamiliar or poorly calibrated for palette distinguishability. Spec: [[file:docs/design/theme-studio-perceptual-color-metrics-spec.org][spec]] (vNext candidates; review folded in 2026-06-08). ** TODO [#B] Dashboard keybinding changes :quick: :PROPERTIES: :LAST_REVIEWED: 2026-06-06 @@ -7170,4 +7219,3 @@ Expected: F12 excludes agent buffers and keeps saved geometry; the dashboard lau What we're verifying: the aiv- tmux session survives an Emacs crash and reattaches. - with a live agent, kill Emacs (not the tmux session); restart Emacs; F9 → project picker Expected: the project shows "[detached]" and reattaches to the surviving tmux session. - |
