@riebeckite/theme-minimal 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,66 +1,140 @@
1
- # @riebeckite/theme-minimal
2
-
3
- A deliberately plain baseline theme for Riebeckite: monochrome paper/ink, no
4
- decorative base styling. Use it as a reference implementation of every theme
5
- authoring rule, or as a blank canvas for your own theme.
6
-
7
- [日本語](./README_ja.md)
8
-
9
- ## Overview
10
-
11
- `minimalTheme()` creates a theme named `minimal`. It is the smallest valid
12
- Theme that still follows the [theme authoring contract](../../../docs/theme_authoring_en.md):
13
- it exposes the full set of `--rb-*` semantic tokens, maps them into an
14
- `@theme` block, and only touches token values — no `data-*` attributes, no
15
- custom base rules beyond `html`/`body`/`::selection`/`:focus-visible`.
16
-
17
- ## Usage
18
-
19
- ```ts
20
- import { defineConfig } from "@riebeckite/core";
21
- import { minimalTheme } from "@riebeckite/theme-minimal";
22
-
23
- export default defineConfig({
24
- // ...
25
- theme: minimalTheme({
26
- colorMode: "system",
27
- typography: "system",
28
- articleLayout: "article",
29
- userCss: [],
30
- }),
31
- });
32
- ```
33
-
34
- Uses the same `ThemeConfig` API as `defaultTheme()`, so it can replace any
35
- other theme without configuration changes. The root-level `data-theme-name`
36
- attribute reports `minimal`.
37
-
38
- ## Options
39
-
40
- `minimalTheme(options?)` accepts any `ThemeConfig` field except `name`:
41
-
42
- | Option | Type | Default | Description |
43
- | ------ | ---- | ------- | ----------- |
44
- | `colorMode` | `"light" \| "dark" \| "system"` | `"system"` | Color mode. `system` follows `prefers-color-scheme` unless `data-theme` is set |
45
- | `typography` | `"system" \| "serif" \| "sans"` | `"system"` | Typography preset, applied via the `data-typography` attribute |
46
- | `articleLayout` | `"article" \| "sidebar" \| "full-width"` | `"article"` | Article layout preset for consumers that read `data-article-layout` |
47
- | `tokens` | `ThemeDesignTokens` | `{}` | Override design tokens (colors, fonts, spacing, layout widths) |
48
- | `userCss` | `string[]` | `[]` | Extra user stylesheets |
49
-
50
- See the [`@riebeckite/theme-default`](../default/README.md) README for the
51
- full token list — the token contract is identical.
52
-
53
- ## Exports
54
-
55
- - `minimalTheme(options?)` — theme factory
56
- - Type: `MinimalThemeOptions`
57
- - Styles: `@riebeckite/theme-minimal/style.css`
58
-
59
- ## See also
60
-
61
- - [Theme authoring contract](../../../docs/theme_authoring_en.md)
62
- - [`@riebeckite/theme-default`](../default/README.md)
63
- - [`@riebeckite/theme-sakura`](../sakura/README.md)
64
- - [`@riebeckite/theme-tokyonight`](../tokyonight/README.md)
65
- - [`@riebeckite/theme-gruvbox`](../gruvbox/README.md)
66
- - [`@riebeckite/theme-rerurate`](../rerurate/README.md)
1
+ # @riebeckite/theme-minimal
2
+
3
+ A content-first, near-chromeless typographic theme for Riebeckite: "nothing but
4
+ type and space". Monochrome paper/ink, system fonts only, no bundled fonts and
5
+ no JavaScript.
6
+
7
+ [日本語](./README_ja.md)
8
+
9
+ ## Overview
10
+
11
+ `minimalTheme()` creates a theme named `minimal`. Under the hood it exposes
12
+ the full set of `--rb-*` semantic tokens and maps them into an `@theme` block,
13
+ then layers a typographic character on top of the stable structural hooks
14
+ (`.rb-article-*`, `.rb-sidebar`, `.prose`) and the plugin roots (`rr-*`) — all
15
+ scoped to `[data-theme-name="minimal"]` and kept outside `@layer base`.
16
+
17
+ It is a Riebeckite-native implementation of the design principles behind
18
+ [Minimal for Obsidian](https://github.com/kepano/obsidian-minimal): content
19
+ first, a quiet interface, strong typography, restrained accent, and dense but
20
+ readable chrome. Those ideas are translated into Riebeckite semantic tokens and
21
+ stable hooks. It does not imitate the Obsidian desktop app and assumes no
22
+ Obsidian variables or DOM.
23
+
24
+ The character is restraint:
25
+
26
+ - **A close measure.** The article column is tightened to `43rem` so lines
27
+ stay comfortably readable without growing the page chrome.
28
+ - **Type first.** Headings are differentiated by size, weight and tracking —
29
+ not colour, rules or boxes. Body text runs at a generous line-height with
30
+ open paragraph spacing.
31
+ - **Hairlines over fills.** Blockquotes, code, tables, the article meta/footer
32
+ and plugin roots use 1px borders and transparent or barely-there surfaces
33
+ instead of cards, fills or shadows. Corners are square.
34
+ - **Near-chromeless colour.** The only accent is ink itself; links are ink with
35
+ a quiet underline that firms up on hover. Accent is limited to links, the
36
+ focus/active state and selection.
37
+
38
+ It replaces `defaultTheme()` without configuration changes and reports
39
+ `data-theme-name="minimal"` on the root.
40
+
41
+ ## Installation
42
+
43
+ ```sh
44
+ pnpm add @riebeckite/theme-minimal
45
+ ```
46
+
47
+ The package depends on `@riebeckite/core` and ships as CSS only — no runtime
48
+ code and no bundled font files.
49
+
50
+ ## Usage
51
+
52
+ ```ts
53
+ import { defineConfig } from "@riebeckite/core";
54
+ import { minimalTheme } from "@riebeckite/theme-minimal";
55
+
56
+ export default defineConfig({
57
+ // ...
58
+ theme: minimalTheme({
59
+ colorMode: "system",
60
+ typography: "system",
61
+ articleLayout: "article",
62
+ userCss: [],
63
+ }),
64
+ });
65
+ ```
66
+
67
+ Uses the same `ThemeConfig` API as `defaultTheme()`, so it can replace any
68
+ other theme without configuration changes. The root-level `data-theme-name`
69
+ attribute reports `minimal`.
70
+
71
+ ## Options
72
+
73
+ `minimalTheme(options?)` accepts any `ThemeConfig` field except `name`:
74
+
75
+ | Option | Type | Default | Description |
76
+ | ------ | ---- | ------- | ----------- |
77
+ | `colorMode` | `"light" \| "dark" \| "system"` | `"system"` | Color mode. `system` follows `prefers-color-scheme` unless `data-theme` is set |
78
+ | `typography` | `"system" \| "serif" \| "sans"` | `"system"` | Typography preset, applied via the `data-typography` attribute |
79
+ | `articleLayout` | `"article" \| "sidebar" \| "full-width"` | `"article"` | Article layout preset for consumers that read `data-article-layout` |
80
+ | `tokens` | `ThemeDesignTokens` | `{}` | Override design tokens (colors, fonts, spacing, layout widths) |
81
+ | `userCss` | `string[]` | `[]` | Extra user stylesheets |
82
+
83
+ See the [`@riebeckite/theme-default`](../default/README.md) README for the
84
+ full token list — the token contract is identical.
85
+
86
+ ## Light and dark
87
+
88
+ The palette is deliberately neutral rather than tinted.
89
+
90
+ - **Light** — a near-white reading surface (`#ffffff`), a subtly
91
+ differentiated secondary surface (`#f7f7f7` / `#ececec`), a dark neutral ink
92
+ (`#1a1a1a`), softer muted text (`#6b6b6b`), low-contrast hairlines, and ink
93
+ as the restrained accent.
94
+ - **Dark** — a neutral dark surface (`#1a1a1a`) with slightly lifted secondary
95
+ surfaces (`#242424` / `#2e2e2e`), soft off-white text (`#e5e5e5`), restrained
96
+ muted text (`#9e9e9e`), subtle separators, and the same ink-as-accent
97
+ treatment. There is no pure black, glow or oversaturated accent.
98
+
99
+ `colorMode: "system"` leaves `data-theme` unset so the OS preference decides;
100
+ setting `"light"` or `"dark"` writes the matching `data-theme` value. Links,
101
+ focus rings, active controls and selection all use the same accent (ink) so
102
+ they stay clearly visible and AA-contrast in both modes.
103
+
104
+ ## Background contrast variants
105
+
106
+ Upstream Minimal ships background-contrast variants (default, low contrast,
107
+ high contrast, true black). The Riebeckite Theme API has no variant concept
108
+ today, so this theme ships its normal appearance as the default and expresses
109
+ the surface hierarchy through semantic tokens (`--rb-color-paper`,
110
+ `--rb-color-surface`, `--rb-color-surface-hover`,
111
+ `--rb-color-code-background`). The `tokens` option can already remap those per
112
+ site. Background-contrast variants are a possible future Theme API extension
113
+ rather than something the theme fakes with extra attributes.
114
+
115
+ ## Exports
116
+
117
+ - `minimalTheme(options?)` — theme factory
118
+ - Type: `MinimalThemeOptions`
119
+ - Styles: `@riebeckite/theme-minimal/style.css`
120
+
121
+ ## Attribution
122
+
123
+ Riebeckite theme based on the design principles of Minimal for Obsidian by Steph Ango (kepano).
124
+
125
+ - Upstream: <https://github.com/kepano/obsidian-minimal>
126
+ - Upstream license: MIT
127
+
128
+ This is an independent Riebeckite implementation of those design ideas, built
129
+ from Riebeckite semantic tokens and stable hooks. It is not the official
130
+ Obsidian Minimal distribution and does not emulate the Obsidian desktop app. It
131
+ is distributed here under the license stated in the package `LICENSE` file.
132
+
133
+ ## See also
134
+
135
+ - [Theme authoring contract](../../../docs/en/theme-system.md)
136
+ - [`@riebeckite/theme-default`](../default/README.md)
137
+ - [`@riebeckite/theme-sakura`](../sakura/README.md)
138
+ - [`@riebeckite/theme-tokyonight`](../tokyonight/README.md)
139
+ - [`@riebeckite/theme-gruvbox`](../gruvbox/README.md)
140
+ - [`@riebeckite/theme-rerurate`](../rerurate/README.md)
package/README_ja.md CHANGED
@@ -1,54 +1,96 @@
1
- # @riebeckite/theme-minimal
2
-
3
- 色と基本トークンだけを提供する、もっとも小さな Riebeckite テーマです。装飾的なベーススタイルを持たないため、自作テーマの出発点やテーマ実装の参照に向いています。
4
-
5
- [English](./README.md)
6
-
7
- ## 何をするテーマか
8
-
9
- `minimalTheme()` は名前が `minimal` のテーマを作ります。完全な `--rb-*` トークンと `@theme` の対応は持ちますが、トークン値以外の見た目には手を加えません。テーマ固有の `data-*` 属性や、`html`、`body`、`::selection`、`:focus-visible` への追加ルールもありません。
10
-
11
- 独自 CSS の影響を見極めたいときや、独自テーマを小さく始めたいときに選んでください。
12
-
13
- ## 設定する
14
-
15
- ```ts
16
- import { defineConfig } from "@riebeckite/core";
17
- import { minimalTheme } from "@riebeckite/theme-minimal";
18
-
19
- export default defineConfig({
20
- // ...
21
- theme: minimalTheme({
22
- colorMode: "system",
23
- typography: "system",
24
- articleLayout: "article",
25
- }),
26
- });
27
- ```
28
-
29
- ## 変更できる項目
30
-
31
- | 項目 | 既定値 | 説明 |
32
- | --- | --- | --- |
33
- | `colorMode` | `"system"` | `"light"`、`"dark"`、`"system"` |
34
- | `typography` | `"system"` | `"system"`、`"serif"`、`"sans"` |
35
- | `articleLayout` | `"article"` | 記事レイアウトの値 |
36
- | `tokens` | `{}` | 色、フォント、余白、レイアウト幅のトークンを上書きする |
37
- | `userCss` | `[]` | 追加のスタイルシート |
38
-
39
- トークンの意味と一覧は [`@riebeckite/theme-default`](../default/README_ja.md) を参照してください。
40
-
41
- ## 主なエクスポート
42
-
43
- - `minimalTheme(options?)`: テーマを作成する
44
- - `MinimalThemeOptions`: 設定用の型
45
- - `@riebeckite/theme-minimal/style.css`: テーマのスタイルシート
46
-
47
- ## 関連資料
48
-
49
- - [テーマシステム](../../../docs/ja/theme-system.md)
50
- - [`@riebeckite/theme-default`](../default/README_ja.md)
51
- - [`@riebeckite/theme-sakura`](../sakura/README_ja.md)
52
- - [`@riebeckite/theme-tokyonight`](../tokyonight/README_ja.md)
53
- - [`@riebeckite/theme-gruvbox`](../gruvbox/README_ja.md)
54
- - [`@riebeckite/theme-rerurate`](../rerurate/README_ja.md)
1
+ # @riebeckite/theme-minimal
2
+
3
+ 内容が主役で、装飾をほとんど持たないタイポグラフィ主体のテーマです。「文字と余白だけ」を方針に、モノクロの紙とインクで構成します。使うのはシステムフォントだけ、同梱フォントも JavaScript もありません。
4
+
5
+ [English](./README.md)
6
+
7
+ ## 何をするテーマか
8
+
9
+ `minimalTheme()` は名前が `minimal` のテーマを作ります。完全な `--rb-*` トークンを `@theme` に対応させたうえで、安定した構造フック(`.rb-article-*`、`.rb-sidebar`、`.prose`)とプラグインのルート(`rr-*`)にタイポグラフィの個性を重ねます。指定はすべて `[data-theme-name="minimal"]` にスコープし、`@layer base` の外に置いています。
10
+
11
+ [Minimal for Obsidian](https://github.com/kepano/obsidian-minimal) の設計思想——内容が主役、静かな操作画面、強いタイポグラフィ、控えめなアクセント、詰まっていても読みやすいクローム——を、Riebeckite のセマンティックトークンと安定フックに置き換えて実装したものです。Obsidian デスクトップアプリの見た目を模したり、Obsidian の変数や DOM があることを前提にしたりはしません。
12
+
13
+ 個性は引き算にあります。
14
+
15
+ - **狭い行長。** 記事カラムを `43rem` に絞り、ページのクロームを増やさずに一行の長さを読みやすく保ちます。
16
+ - **文字が主役。** 見出しは大きさ、太さ、字間で差をつけ、色・罫線・囲みは使いません。本文は行間を広めに取り、段落の余白もゆったりさせます。
17
+ - **塗りより罫線。** 引用、コード、表、記事メタ/フッター、プラグインのルートは、カードや塗り、影ではなく 1px の罫線とごく薄い背景(または背景なし)で扱います。角は直角のままです。
18
+ - **ほぼ無彩色。** アクセントはインクそのものだけ。リンクはインク色で、控えめな下線をホバーで少し強めます。アクセントを使うのはリンク、フォーカス/選択状態、操作部品に限ります。
19
+
20
+ 設定を変えずに `defaultTheme()` を置き換えられ、ルートに `data-theme-name="minimal"` を報告します。
21
+
22
+ ## インストール
23
+
24
+ ```sh
25
+ pnpm add @riebeckite/theme-minimal
26
+ ```
27
+
28
+ `@riebeckite/core` に依存し、配布物は CSS のみです。実行時のコードや同梱フォントは含みません。
29
+
30
+ ## 設定する
31
+
32
+ ```ts
33
+ import { defineConfig } from "@riebeckite/core";
34
+ import { minimalTheme } from "@riebeckite/theme-minimal";
35
+
36
+ export default defineConfig({
37
+ // ...
38
+ theme: minimalTheme({
39
+ colorMode: "system",
40
+ typography: "system",
41
+ articleLayout: "article",
42
+ userCss: [],
43
+ }),
44
+ });
45
+ ```
46
+
47
+ `defaultTheme()` と同じ `ThemeConfig` API なので、設定を変えずにほかのテーマと入れ替えられます。ルートの `data-theme-name` は `minimal` になります。
48
+
49
+ ## 変更できる項目
50
+
51
+ | 項目 | 既定値 | 説明 |
52
+ | --- | --- | --- |
53
+ | `colorMode` | `"system"` | `"light"`、`"dark"`、`"system"` |
54
+ | `typography` | `"system"` | `"system"`、`"serif"`、`"sans"` |
55
+ | `articleLayout` | `"article"` | 記事レイアウトの値 |
56
+ | `tokens` | `{}` | 色、フォント、余白、レイアウト幅のトークンを上書きする |
57
+ | `userCss` | `[]` | 追加のスタイルシート |
58
+
59
+ トークンの意味と一覧は [`@riebeckite/theme-default`](../default/README_ja.md) を参照してください。トークン契約は同じです。
60
+
61
+ ## ライトとダーク
62
+
63
+ パレットはわざと色味を持たせず、無彩でまとめています。
64
+
65
+ - **ライト** — ほぼ白の読書面(`#ffffff`)、わずかに差をつけた副次サーフェス(`#f7f7f7` / `#ececec`)、濃いニュートラルのインク(`#1a1a1a`)、やわらかい副次テキスト(`#6b6b6b`)、低コントラストの罫線、そしてアクセントとしてのインク。
66
+ - **ダーク** — ニュートラルな暗い背景(`#1a1a1a`)と、わずかに持ち上げた副次サーフェス(`#242424` / `#2e2e2e`)、やわらかいオフホワイトの本文(`#e5e5e5`)、抑制した補助テキスト(`#9e9e9e`)、控えめな区切り、同じインク基調のアクセント。純黒や発光、彩度の高いアクセントは使いません。
67
+
68
+ `colorMode: "system"` では `data-theme` を付けず OS の設定に従います。`"light"` または `"dark"` を指定すると対応する `data-theme` が付きます。リンク、フォーカスリング、選択中の操作部品、選択範囲はいずれも同じインクのアクセントを使うため、どちらのモードでもはっきり見え、AA コントラストを満たします。
69
+
70
+ ## 背景コントラストのバリエーション
71
+
72
+ 本家 Minimal には背景コントラストのバリエーション(既定、低コントラスト、高コントラスト、トゥルーブラック)があります。いまの Riebeckite の Theme API にはバリエーションの概念がないため、このテーマは通常の見た目を既定として提供し、サーフェスの階層をセマンティックトークン(`--rb-color-paper`、`--rb-color-surface`、`--rb-color-surface-hover`、`--rb-color-code-background`)で表現しています。`tokens` オプションでサイトごとに上書きすることはすでに可能です。背景コントラストのバリエーションは、独自属性で見せかけるのではなく、将来 Theme API に追加できる拡張候補です。
73
+
74
+ ## 主なエクスポート
75
+
76
+ - `minimalTheme(options?)`: テーマを作成する
77
+ - `MinimalThemeOptions`: 設定用の型
78
+ - `@riebeckite/theme-minimal/style.css`: テーマのスタイルシート
79
+
80
+ ## 出典
81
+
82
+ Riebeckite theme based on the design principles of Minimal for Obsidian by Steph Ango (kepano).
83
+
84
+ - 原典: <https://github.com/kepano/obsidian-minimal>
85
+ - 原典のライセンス: MIT
86
+
87
+ このパッケージは、これらの設計思想を Riebeckite のセマンティックトークンと安定フックで独立に実装したものです。Obsidian Minimal の公式配布物ではなく、Obsidian デスクトップアプリを模したものでもありません。配布条件はパッケージの `LICENSE` ファイルに記載しています。
88
+
89
+ ## 関連資料
90
+
91
+ - [テーマシステム](../../../docs/ja/theme-system.md)
92
+ - [`@riebeckite/theme-default`](../default/README_ja.md)
93
+ - [`@riebeckite/theme-sakura`](../sakura/README_ja.md)
94
+ - [`@riebeckite/theme-tokyonight`](../tokyonight/README_ja.md)
95
+ - [`@riebeckite/theme-gruvbox`](../gruvbox/README_ja.md)
96
+ - [`@riebeckite/theme-rerurate`](../rerurate/README_ja.md)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riebeckite/theme-minimal",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
@@ -16,7 +16,7 @@
16
16
  "./styles/theme.css": "./styles/theme.css"
17
17
  },
18
18
  "dependencies": {
19
- "@riebeckite/core": "0.0.5"
19
+ "@riebeckite/core": "0.0.6"
20
20
  },
21
21
  "publishConfig": {
22
22
  "access": "public"
package/styles/theme.css CHANGED
@@ -1,106 +1,537 @@
1
- @theme {
2
- --font-sans: var(--rb-font-body);
3
- --font-serif: Georgia, Cambria, "Times New Roman", Times, serif;
4
- --font-mono: var(--rb-font-mono);
5
- --color-rb-paper: var(--rb-color-paper);
6
- --color-rb-ink: var(--rb-color-ink);
7
- --color-rb-muted: var(--rb-color-muted);
8
- --color-rb-accent: var(--rb-color-accent);
9
- --color-rb-surface: var(--rb-color-surface);
10
- --color-rb-danger: var(--rb-color-danger);
11
- --color-rb-success: var(--rb-color-success);
12
- }
13
-
14
- @layer base {
15
- :root {
16
- color-scheme: light;
17
- --rb-color-paper: #ffffff;
18
- --rb-color-surface: #f7f7f7;
19
- --rb-color-surface-hover: #ececec;
20
- --rb-color-ink: #1a1a1a;
21
- --rb-color-muted: #737373;
22
- --rb-color-accent: #1a1a1a;
23
- --rb-color-border: color-mix(in srgb, currentColor 18%, transparent);
24
- --rb-color-border-strong: color-mix(in srgb, currentColor 28%, transparent);
25
- --rb-color-danger: #b42318;
26
- --rb-color-success: #047857;
27
- --rb-color-code-background: #f2f2f2;
28
- --rb-color-overlay: rgb(0 0 0 / 0.4);
29
- --rb-font-body: ui-sans-serif, system-ui, sans-serif;
30
- --rb-font-heading: var(--rb-font-body);
31
- --rb-font-mono: "SFMono-Regular", Consolas, monospace;
32
- --rb-space-1: 0.5rem;
33
- --rb-space-2: 1rem;
34
- --rb-space-3: 1.5rem;
35
- --rb-space-4: 2rem;
36
- --rb-space-6: 3rem;
37
- --rb-space-8: 4rem;
38
- --rb-rule-width: 1px;
39
- --rb-layout-page-max: 80rem;
40
- --rb-layout-article-max: 48rem;
41
- --rb-layout-sidebar: 14rem;
42
- --rb-layout-gap: 2rem;
43
- }
44
-
45
- :root[data-theme="dark"] {
46
- color-scheme: dark;
47
- --rb-color-paper: #1a1a1a;
48
- --rb-color-surface: #242424;
49
- --rb-color-surface-hover: #2e2e2e;
50
- --rb-color-ink: #e5e5e5;
51
- --rb-color-muted: #9e9e9e;
52
- --rb-color-accent: #e5e5e5;
53
- --rb-color-danger: #e5484d;
54
- --rb-color-success: #30a46c;
55
- --rb-color-code-background: #262626;
56
- --rb-color-overlay: rgb(0 0 0 / 0.6);
57
- }
58
-
59
- @media (prefers-color-scheme: dark) {
60
- :root:not([data-theme]) {
61
- color-scheme: dark;
62
- --rb-color-paper: #1a1a1a;
63
- --rb-color-surface: #242424;
64
- --rb-color-surface-hover: #2e2e2e;
65
- --rb-color-ink: #e5e5e5;
66
- --rb-color-muted: #9e9e9e;
67
- --rb-color-accent: #e5e5e5;
68
- --rb-color-danger: #e5484d;
69
- --rb-color-success: #30a46c;
70
- --rb-color-code-background: #262626;
71
- --rb-color-overlay: rgb(0 0 0 / 0.6);
72
- }
73
- }
74
-
75
- :root[data-typography="serif"] {
76
- --rb-font-body: Georgia, Cambria, "Times New Roman", Times, serif;
77
- --rb-font-heading: ui-sans-serif, system-ui, sans-serif;
78
- }
79
-
80
- :root[data-typography="sans"] {
81
- --rb-font-body: ui-sans-serif, system-ui, sans-serif;
82
- --rb-font-heading: var(--rb-font-body);
83
- }
84
-
85
- html {
86
- background: var(--rb-color-paper);
87
- color: var(--rb-color-ink);
88
- font-family: var(--rb-font-body);
89
- }
90
-
91
- body {
92
- margin: 0;
93
- background: var(--rb-color-paper);
94
- color: var(--rb-color-ink);
95
- }
96
-
97
- ::selection {
98
- background: var(--rb-color-accent);
99
- color: var(--rb-color-paper);
100
- }
101
-
102
- :focus-visible {
103
- outline: 2px solid var(--rb-color-accent);
104
- outline-offset: 2px;
105
- }
106
- }
1
+ @theme {
2
+ --font-sans: var(--rb-font-body);
3
+ --font-serif: Georgia, Cambria, "Times New Roman", Times, serif;
4
+ --font-mono: var(--rb-font-mono);
5
+ --color-rb-paper: var(--rb-color-paper);
6
+ --color-rb-ink: var(--rb-color-ink);
7
+ --color-rb-muted: var(--rb-color-muted);
8
+ --color-rb-accent: var(--rb-color-accent);
9
+ --color-rb-surface: var(--rb-color-surface);
10
+ --color-rb-danger: var(--rb-color-danger);
11
+ --color-rb-success: var(--rb-color-success);
12
+ }
13
+
14
+ @layer base {
15
+ /* Surface hierarchy is carried by semantic tokens rather than fixed shades
16
+ (`paper` → `surface` → `surface-hover`), so a future background-contrast
17
+ variant could remap these three values without touching the character
18
+ layer. See the README for the upstream contrast variants. */
19
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] {
20
+ color-scheme: light;
21
+ --rb-color-paper: #ffffff;
22
+ --rb-color-surface: #f7f7f7;
23
+ --rb-color-surface-hover: #ececec;
24
+ --rb-color-ink: #1a1a1a;
25
+ --rb-color-muted: #6b6b6b;
26
+ --rb-color-accent: #1a1a1a;
27
+ --rb-color-border: color-mix(in srgb, currentColor 18%, transparent);
28
+ --rb-color-border-strong: color-mix(in srgb, currentColor 28%, transparent);
29
+ --rb-color-danger: #b42318;
30
+ --rb-color-success: #047857;
31
+ --rb-color-code-background: #f2f2f2;
32
+ --rb-color-overlay: rgb(0 0 0 / 0.4);
33
+ --rb-font-body: ui-sans-serif, system-ui, sans-serif;
34
+ --rb-font-heading: var(--rb-font-body);
35
+ --rb-font-mono: "SFMono-Regular", Consolas, monospace;
36
+ --rb-space-1: 0.5rem;
37
+ --rb-space-2: 1rem;
38
+ --rb-space-3: 1.5rem;
39
+ --rb-space-4: 2rem;
40
+ --rb-space-6: 3rem;
41
+ --rb-space-8: 4rem;
42
+ --rb-rule-width: 1px;
43
+ --rb-layout-page-max: 80rem;
44
+ --rb-layout-article-max: 43rem;
45
+ --rb-layout-sidebar: 14rem;
46
+ --rb-layout-gap: 2rem;
47
+ }
48
+
49
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"][data-theme="dark"] {
50
+ color-scheme: dark;
51
+ --rb-color-paper: #1a1a1a;
52
+ --rb-color-surface: #242424;
53
+ --rb-color-surface-hover: #2e2e2e;
54
+ --rb-color-ink: #e5e5e5;
55
+ --rb-color-muted: #9e9e9e;
56
+ --rb-color-accent: #e5e5e5;
57
+ --rb-color-danger: #e5484d;
58
+ --rb-color-success: #30a46c;
59
+ --rb-color-code-background: #262626;
60
+ --rb-color-overlay: rgb(0 0 0 / 0.6);
61
+ }
62
+
63
+ @media (prefers-color-scheme: dark) {
64
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]:not([data-theme]) {
65
+ color-scheme: dark;
66
+ --rb-color-paper: #1a1a1a;
67
+ --rb-color-surface: #242424;
68
+ --rb-color-surface-hover: #2e2e2e;
69
+ --rb-color-ink: #e5e5e5;
70
+ --rb-color-muted: #9e9e9e;
71
+ --rb-color-accent: #e5e5e5;
72
+ --rb-color-danger: #e5484d;
73
+ --rb-color-success: #30a46c;
74
+ --rb-color-code-background: #262626;
75
+ --rb-color-overlay: rgb(0 0 0 / 0.6);
76
+ }
77
+ }
78
+
79
+ :is(
80
+ :root,
81
+ .rb-theme-root
82
+ )[data-theme-name="minimal"][data-typography="serif"] {
83
+ --rb-font-body: Georgia, Cambria, "Times New Roman", Times, serif;
84
+ --rb-font-heading: ui-sans-serif, system-ui, sans-serif;
85
+ }
86
+
87
+ :is(
88
+ :root,
89
+ .rb-theme-root
90
+ )[data-theme-name="minimal"][data-typography="sans"] {
91
+ --rb-font-body: ui-sans-serif, system-ui, sans-serif;
92
+ --rb-font-heading: var(--rb-font-body);
93
+ }
94
+
95
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] {
96
+ background: var(--rb-color-paper);
97
+ color: var(--rb-color-ink);
98
+ font-family: var(--rb-font-body);
99
+ accent-color: var(--rb-color-accent);
100
+ caret-color: var(--rb-color-accent);
101
+ }
102
+ }
103
+
104
+ /* ------------------------------------------------------------------ *
105
+ * Character layer
106
+ *
107
+ * Minimal identity: nothing but type and space. A deliberately close
108
+ * reading measure (~43rem), generous leading and paragraph rhythm,
109
+ * headings differentiated by size/weight/tracking instead of colour or
110
+ * boxes, and hairlines only where structure genuinely needs a boundary.
111
+ * Near-chromeless: the only accent is ink itself. Unlayered on purpose
112
+ * so it wins over the layered app and plugin stylesheets without
113
+ * `!important`.
114
+ * ------------------------------------------------------------------ */
115
+
116
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] ::selection {
117
+ background: var(--rb-color-accent);
118
+ color: var(--rb-color-paper);
119
+ }
120
+
121
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] :focus-visible {
122
+ outline: 2px solid var(--rb-color-accent);
123
+ outline-offset: 2px;
124
+ }
125
+
126
+ /* ---- Body rhythm: open leading, generous paragraphs. ---- */
127
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-article-body {
128
+ font-family: var(--rb-font-body);
129
+ font-size: 1.0625rem;
130
+ line-height: 1.85;
131
+ }
132
+
133
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-article-body p {
134
+ margin: 1.2em 0;
135
+ text-wrap: pretty;
136
+ }
137
+
138
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
139
+ .rb-article-body
140
+ :is(ul, ol) {
141
+ margin: 1.35em 0;
142
+ padding-left: 1.5em;
143
+ }
144
+
145
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
146
+ .rb-article-body
147
+ :is(ul, ol)
148
+ :is(ul, ol) {
149
+ margin: 0.5em 0;
150
+ }
151
+
152
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-article-body li {
153
+ margin: 0.5em 0;
154
+ padding-left: 0.15em;
155
+ }
156
+
157
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
158
+ .rb-article-body
159
+ li::marker {
160
+ color: var(--rb-color-muted);
161
+ }
162
+
163
+ /* ---- Headings: size, weight and tracking do the work. ---- */
164
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-article-header {
165
+ margin-bottom: 2.5rem;
166
+ }
167
+
168
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-article-header h1 {
169
+ font-family: var(--rb-font-heading);
170
+ font-size: clamp(1.9rem, 1.5rem + 1.4vw, 2.4rem);
171
+ font-weight: 700;
172
+ line-height: 1.15;
173
+ letter-spacing: -0.02em;
174
+ text-wrap: balance;
175
+ }
176
+
177
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-article-body h2 {
178
+ margin: 3.25rem 0 1rem;
179
+ padding-top: 1.75rem;
180
+ border-top: 1px solid var(--rb-color-border);
181
+ font-family: var(--rb-font-heading);
182
+ font-size: 1.4rem;
183
+ font-weight: 600;
184
+ line-height: 1.3;
185
+ letter-spacing: -0.012em;
186
+ text-wrap: balance;
187
+ }
188
+
189
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-article-body h3 {
190
+ margin: 2.25rem 0 0.75rem;
191
+ font-family: var(--rb-font-heading);
192
+ font-size: 1.125rem;
193
+ font-weight: 600;
194
+ line-height: 1.35;
195
+ letter-spacing: -0.005em;
196
+ }
197
+
198
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-article-body h4 {
199
+ margin: 1.9rem 0 0.6rem;
200
+ font-family: var(--rb-font-heading);
201
+ font-size: 1rem;
202
+ font-weight: 600;
203
+ line-height: 1.4;
204
+ letter-spacing: 0.01em;
205
+ }
206
+
207
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
208
+ .rb-article-body
209
+ :is(h5, h6) {
210
+ margin: 1.6rem 0 0.5rem;
211
+ font-family: var(--rb-font-heading);
212
+ font-size: 0.8125rem;
213
+ font-weight: 600;
214
+ letter-spacing: 0.08em;
215
+ text-transform: uppercase;
216
+ color: var(--rb-color-muted);
217
+ }
218
+
219
+ /* ---- Links: ink, with a quiet underline that firms up on hover. ---- */
220
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
221
+ :is(.rb-article-body, .rb-article-footer, .rb-article-meta)
222
+ a {
223
+ color: var(--rb-color-ink);
224
+ text-decoration: underline;
225
+ text-decoration-color: color-mix(
226
+ in srgb,
227
+ var(--rb-color-ink) 30%,
228
+ transparent
229
+ );
230
+ text-decoration-thickness: 1px;
231
+ text-underline-offset: 0.25em;
232
+ }
233
+
234
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
235
+ :is(.rb-article-body, .rb-article-footer, .rb-article-meta)
236
+ a:hover {
237
+ text-decoration-color: var(--rb-color-ink);
238
+ }
239
+
240
+ /* ---- Blockquote: a single hairline, muted ink, no fill. ---- */
241
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
242
+ .rb-article-body
243
+ blockquote {
244
+ margin: 2rem 0;
245
+ padding: 0.1rem 0 0.1rem 1.25rem;
246
+ border: 0;
247
+ border-left: 1px solid var(--rb-color-border-strong);
248
+ background: none;
249
+ color: color-mix(in srgb, var(--rb-color-ink) 78%, var(--rb-color-muted));
250
+ font-style: normal;
251
+ }
252
+
253
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
254
+ .rb-article-body
255
+ blockquote
256
+ p:first-of-type::before,
257
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
258
+ .rb-article-body
259
+ blockquote
260
+ p:last-of-type::after {
261
+ content: none;
262
+ }
263
+
264
+ /* ---- Rules: a low-contrast hairline. ---- */
265
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-article-body hr {
266
+ width: 100%;
267
+ height: 1px;
268
+ margin: 3.5rem 0;
269
+ border: 0;
270
+ background: var(--rb-color-border);
271
+ }
272
+
273
+ /* ---- Inline code: a monochrome chip. ---- */
274
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
275
+ .rb-article-body
276
+ :not(pre)
277
+ > code {
278
+ padding: 0.1em 0.35em;
279
+ border: 1px solid var(--rb-color-border);
280
+ border-radius: 0;
281
+ background: color-mix(in srgb, var(--rb-color-ink) 6%, transparent);
282
+ color: var(--rb-color-ink);
283
+ font-family: var(--rb-font-mono);
284
+ font-size: 0.85em;
285
+ }
286
+
287
+ /* ---- Bare code blocks: flat, hairline border, bare tint. ---- */
288
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
289
+ .rb-article-body
290
+ pre:not(:where(.rr-code *)) {
291
+ margin: 2rem 0;
292
+ padding: 1rem 1.1rem;
293
+ border: 1px solid var(--rb-color-border);
294
+ border-radius: 0;
295
+ background: color-mix(in srgb, var(--rb-color-ink) 4%, transparent);
296
+ color: var(--rb-color-ink);
297
+ font-family: var(--rb-font-mono);
298
+ font-size: 0.85rem;
299
+ line-height: 1.7;
300
+ overflow-x: auto;
301
+ }
302
+
303
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
304
+ .rb-article-body
305
+ pre:not(:where(.rr-code *))
306
+ code {
307
+ padding: 0;
308
+ border: 0;
309
+ background: transparent;
310
+ color: inherit;
311
+ font-size: inherit;
312
+ }
313
+
314
+ /* ---- Tables: hairlines and a quiet, weighted header. ---- */
315
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-article-body table {
316
+ margin: 2rem 0;
317
+ border: 0;
318
+ font-size: 0.95em;
319
+ }
320
+
321
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
322
+ .rb-article-body
323
+ :is(th, td) {
324
+ padding: 0.55em 0.85em;
325
+ border-bottom: 1px solid var(--rb-color-border);
326
+ text-align: start;
327
+ vertical-align: top;
328
+ }
329
+
330
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
331
+ .rb-article-body
332
+ thead
333
+ th {
334
+ border-bottom: 1px solid var(--rb-color-border-strong);
335
+ background: none;
336
+ color: var(--rb-color-ink);
337
+ font-weight: 600;
338
+ }
339
+
340
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
341
+ .rb-article-body
342
+ tbody
343
+ tr:last-child
344
+ :is(th, td) {
345
+ border-bottom: 0;
346
+ }
347
+
348
+ /* ---- Media and embedded plugin frames: square corners. ---- */
349
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
350
+ :is(
351
+ .rb-article-body img,
352
+ .rb-article-body video,
353
+ .rr-media,
354
+ .rr-attachment,
355
+ .rr-excalidraw,
356
+ .rr-query,
357
+ .rr-diff-history
358
+ ) {
359
+ border-radius: 0;
360
+ }
361
+
362
+ /* ---- Article chrome: quiet hairlines. ---- */
363
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-article-meta {
364
+ margin: 0 0 2.5rem;
365
+ padding-block: 0.75rem;
366
+ border-block: 1px solid var(--rb-color-border);
367
+ color: var(--rb-color-muted);
368
+ font-size: 0.8125rem;
369
+ line-height: 1.5;
370
+ letter-spacing: 0.02em;
371
+ }
372
+
373
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-article-footer {
374
+ margin-top: 4rem;
375
+ padding-top: 1.5rem;
376
+ border-top: 1px solid var(--rb-color-border);
377
+ color: var(--rb-color-muted);
378
+ font-size: 0.9rem;
379
+ }
380
+
381
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rb-sidebar {
382
+ padding-left: 1.25rem;
383
+ border-left: 1px solid var(--rb-color-border);
384
+ font-size: 0.9rem;
385
+ line-height: 1.7;
386
+ }
387
+
388
+ /* ---- Plugin roots: hairlines, no fill, room to breathe. ---- */
389
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rr-table-of-contents {
390
+ margin: 2.5rem 0;
391
+ padding: 1.25rem 1.15rem;
392
+ border-radius: 0;
393
+ background: none;
394
+ font-size: 0.9rem;
395
+ line-height: 1.8;
396
+ }
397
+
398
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
399
+ :is(.rr-backlinks, .rr-recent-posts) {
400
+ margin-top: 4rem;
401
+ padding-top: 1.5rem;
402
+ border-top: 1px solid var(--rb-color-border);
403
+ border-radius: 0;
404
+ background: none;
405
+ }
406
+
407
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
408
+ :is(.rr-table-of-contents, .rr-backlinks, .rr-recent-posts)
409
+ a {
410
+ color: var(--rb-color-ink);
411
+ text-decoration: none;
412
+ }
413
+
414
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
415
+ :is(.rr-table-of-contents, .rr-backlinks, .rr-recent-posts)
416
+ a:hover {
417
+ text-decoration: underline;
418
+ text-decoration-thickness: 1px;
419
+ text-underline-offset: 0.25em;
420
+ }
421
+
422
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
423
+ :is(.rr-code, .rr-code-tabs) {
424
+ margin: 2rem 0;
425
+ border: 1px solid var(--rb-color-border);
426
+ border-radius: 0;
427
+ }
428
+
429
+ /* Keep the plugin's code-surface tokens so terminal blocks still invert;
430
+ ordinary blocks resolve to the reading surface. The code-enhance plugin
431
+ owns `.rr-code__pre` / `.rr-code__line` padding, so only the surface colour
432
+ and the flat square frame are themed here. */
433
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rr-code {
434
+ background: var(--rr-code-paper, var(--rb-color-code-background));
435
+ color: var(--rr-code-ink, var(--rb-color-ink));
436
+ }
437
+
438
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rr-code-tabs {
439
+ background: none;
440
+ }
441
+
442
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
443
+ :is(.rr-code, .rr-code-tabs)
444
+ pre {
445
+ margin: 0;
446
+ border: 0;
447
+ border-radius: 0;
448
+ background: transparent;
449
+ color: inherit;
450
+ font-family: var(--rb-font-mono);
451
+ }
452
+
453
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rr-callout {
454
+ margin: 2rem 0;
455
+ padding: 1rem 1.25rem;
456
+ border: 1px solid var(--rb-color-border);
457
+ border-left: 1px solid var(--rb-color-border-strong);
458
+ border-radius: 0;
459
+ background: none;
460
+ box-shadow: none;
461
+ color: var(--rb-color-ink);
462
+ }
463
+
464
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
465
+ .rr-callout
466
+ .callout-title {
467
+ color: var(--rb-color-muted);
468
+ font-family: var(--rb-font-body);
469
+ font-size: 0.8125rem;
470
+ font-weight: 600;
471
+ letter-spacing: normal;
472
+ text-transform: none;
473
+ }
474
+
475
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
476
+ .rr-callout
477
+ .callout-icon {
478
+ color: var(--rb-color-muted);
479
+ }
480
+
481
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rr-callout p:last-child {
482
+ margin-bottom: 0;
483
+ }
484
+
485
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
486
+ :is(.rr-local-graph, .rr-mermaid) {
487
+ border: 1px solid var(--rb-color-border);
488
+ border-radius: 0;
489
+ background: none;
490
+ }
491
+
492
+ /* `.rr-search` is the fixed wrapper, so it carries no frame of its own; the
493
+ plugin's trigger and modal already read the semantic tokens. Square the
494
+ controls and drop the modal shadow to match the flat character. */
495
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
496
+ .rr-search
497
+ :is(input, button, a, kbd) {
498
+ border-radius: 0;
499
+ }
500
+
501
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
502
+ .rr-search
503
+ [role="dialog"] {
504
+ border-radius: 0;
505
+ box-shadow: none;
506
+ }
507
+
508
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rr-cardlink {
509
+ border: 1px solid var(--rb-color-border);
510
+ border-radius: 0;
511
+ background: none;
512
+ color: var(--rb-color-ink);
513
+ text-decoration: none;
514
+ }
515
+
516
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rr-cardlink:hover,
517
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"]
518
+ .rr-cardlink:focus-visible {
519
+ border-color: var(--rb-color-border-strong);
520
+ }
521
+
522
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rr-lightbox img {
523
+ border-radius: 0;
524
+ }
525
+
526
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rr-garden-explorer {
527
+ border: 1px solid var(--rb-color-border);
528
+ border-radius: 0;
529
+ background: none;
530
+ }
531
+
532
+ /* The color-mode toggle is authored as a pill; flatten it to match. Both
533
+ classes are documented plugin hooks (`rr-color-mode`, `rr-color-mode__button`). */
534
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rr-color-mode,
535
+ :is(:root, .rb-theme-root)[data-theme-name="minimal"] .rr-color-mode__button {
536
+ border-radius: 0;
537
+ }