| 9 |
9 |
|
|
| 10 |
10 |
|
The Darkmatter aesthetic: dark, minimal, monospace. No frameworks, no decorative flourishes. Everything is functional and stark. |
| 11 |
11 |
|
|
|
12 |
+ |
The canonical reset, tokens, fonts, and component styles ship in the [`andromeda-darkmatter-css`](https://github.com/stevedylandev/andromeda/tree/main/crates/darkmatter-css) crate. **Do not duplicate the CSS per app** — mount the crate's router and link its stylesheet. |
|
13 |
+ |
|
|
14 |
+ |
## Using the Crate |
|
15 |
+ |
|
|
16 |
+ |
Add to `Cargo.toml`: |
|
17 |
+ |
|
|
18 |
+ |
```toml |
|
19 |
+ |
[dependencies] |
|
20 |
+ |
andromeda-darkmatter-css = { path = "../../crates/darkmatter-css" } |
|
21 |
+ |
``` |
|
22 |
+ |
|
|
23 |
+ |
Mount in the Axum app: |
|
24 |
+ |
|
|
25 |
+ |
```rust |
|
26 |
+ |
let app = Router::new() |
|
27 |
+ |
.route("/", get(index)) |
|
28 |
+ |
.merge(andromeda_darkmatter_css::router()); |
|
29 |
+ |
``` |
|
30 |
+ |
|
|
31 |
+ |
Link from templates: |
|
32 |
+ |
|
|
33 |
+ |
```html |
|
34 |
+ |
<link rel="stylesheet" href="/assets/darkmatter.css" /> |
|
35 |
+ |
<meta name="theme-color" content="#121113" /> |
|
36 |
+ |
``` |
|
37 |
+ |
|
|
38 |
+ |
The crate serves: |
|
39 |
+ |
|
|
40 |
+ |
- `/assets/darkmatter.css` — full stylesheet (reset + tokens + components) |
|
41 |
+ |
- `/assets/fonts/CommitMono-400-Regular.otf`, `…-700-Regular.otf` |
|
42 |
+ |
- `/darkmatter` — live component gallery (reference when building) |
|
43 |
+ |
|
| 12 |
44 |
|
## Core Palette |
| 13 |
45 |
|
|
| 14 |
46 |
|
| Token | Value | Usage | |
|
| 38 |
70 |
|
|
| 39 |
71 |
|
## Typography |
| 40 |
72 |
|
|
| 41 |
|
- |
- **Font:** `"Commit Mono"` (self-hosted .otf), fallback `monospace, sans-serif` |
| 42 |
|
- |
- Applied globally via `* { font-family: ... }` |
|
73 |
+ |
- **Font:** `"Commit Mono"` (served by the crate), fallback `monospace, sans-serif` |
|
74 |
+ |
- Applied globally via the crate's `* { font-family: ... }` |
| 43 |
75 |
|
- **Body font-size:** 14px |
| 44 |
76 |
|
- **Line-height:** 1.6 |
| 45 |
77 |
|
|
|
| 55 |
87 |
|
| 13px | Inline code, error messages | |
| 56 |
88 |
|
| 12px | Nav links, form labels, metadata, dates, table headers, action links | |
| 57 |
89 |
|
|
| 58 |
|
- |
### Font Face Declarations |
| 59 |
|
- |
|
| 60 |
|
- |
```css |
| 61 |
|
- |
@font-face { |
| 62 |
|
- |
font-family: "Commit Mono"; |
| 63 |
|
- |
src: url("/static/fonts/CommitMono-400-Regular.otf") format("opentype"); |
| 64 |
|
- |
font-weight: 400; |
| 65 |
|
- |
font-style: normal; |
| 66 |
|
- |
} |
| 67 |
|
- |
|
| 68 |
|
- |
@font-face { |
| 69 |
|
- |
font-family: "Commit Mono"; |
| 70 |
|
- |
src: url("/static/fonts/CommitMono-700-Regular.otf") format("opentype"); |
| 71 |
|
- |
font-weight: 700; |
| 72 |
|
- |
font-style: normal; |
| 73 |
|
- |
} |
| 74 |
|
- |
``` |
| 75 |
|
- |
|
| 76 |
|
- |
## Base Reset |
| 77 |
|
- |
|
| 78 |
|
- |
```css |
| 79 |
|
- |
* { |
| 80 |
|
- |
padding: 0; |
| 81 |
|
- |
margin: 0; |
| 82 |
|
- |
box-sizing: border-box; |
| 83 |
|
- |
font-family: "Commit Mono", monospace, sans-serif; |
| 84 |
|
- |
scrollbar-width: none; |
| 85 |
|
- |
-ms-overflow-style: none; |
| 86 |
|
- |
} |
| 87 |
|
- |
|
| 88 |
|
- |
html { |
| 89 |
|
- |
background: #121113; |
| 90 |
|
- |
color: #ffffff; |
| 91 |
|
- |
font-size: 14px; |
| 92 |
|
- |
line-height: 1.6; |
| 93 |
|
- |
} |
|
90 |
+ |
## Shared Component Classes |
| 94 |
91 |
|
|
| 95 |
|
- |
html::-webkit-scrollbar { |
| 96 |
|
- |
display: none; |
| 97 |
|
- |
} |
| 98 |
|
- |
``` |
| 99 |
|
- |
|
| 100 |
|
- |
## Layout |
| 101 |
|
- |
|
| 102 |
|
- |
Single-column, centered, max 700px wide. No top body padding — top spacing comes from header `margin-top`: |
| 103 |
|
- |
|
| 104 |
|
- |
```css |
| 105 |
|
- |
body { |
| 106 |
|
- |
display: flex; |
| 107 |
|
- |
flex-direction: column; |
| 108 |
|
- |
justify-content: start; |
| 109 |
|
- |
align-items: start; |
| 110 |
|
- |
gap: 1.5rem; |
| 111 |
|
- |
min-height: 100vh; |
| 112 |
|
- |
max-width: 700px; |
| 113 |
|
- |
margin: auto; |
| 114 |
|
- |
padding: 0 1rem; |
| 115 |
|
- |
} |
|
92 |
+ |
The stylesheet ships ready-to-use classes. Prefer these over writing new rules: |
| 116 |
93 |
|
|
| 117 |
|
- |
@media (max-width: 480px) { |
| 118 |
|
- |
body { |
| 119 |
|
- |
padding: 1rem; |
| 120 |
|
- |
gap: 1rem; |
| 121 |
|
- |
} |
| 122 |
|
- |
} |
| 123 |
|
- |
``` |
|
94 |
+ |
- Layout: `.header`, `.logo`, `.links`, `.footer` |
|
95 |
+ |
- Forms: `.form`, `.form-row`, `.form-field`, `.form-actions`, `.checkbox-field`, `.switch`, `.switch-slider` |
|
96 |
+ |
- Buttons: `button`, `.btn`, `.link-button`, `.link-button.danger` |
|
97 |
+ |
- Lists: `.item-list` / `.item` / `.item-title` / `.item-meta` |
|
98 |
+ |
- Admin lists: `.admin-list`, `.admin-list-item`, `.admin-toolbar`, `.admin-list-actions` |
|
99 |
+ |
- Feedback: `.error`, `.success`, `.empty` |
|
100 |
+ |
- Tags: `.tag`, `.status-badge`, `.status-published`, `.status-draft` |
|
101 |
+ |
- Misc: `.spinner`, `.scroll-x`, `.hidden`, `.inline-form` |
| 124 |
102 |
|
|
| 125 |
|
- |
## Header |
|
103 |
+ |
Visit `/darkmatter` on any app that mounts the crate to see live examples. |
| 126 |
104 |
|
|
| 127 |
|
- |
The header uses a border-bottom separator and `margin-top: 2rem` for top spacing. The site title/logo is **always uppercase**, 28px bold: |
|
105 |
+ |
## Writing New Styles |
| 128 |
106 |
|
|
| 129 |
|
- |
```css |
| 130 |
|
- |
.header { |
| 131 |
|
- |
display: flex; |
| 132 |
|
- |
flex-direction: column; |
| 133 |
|
- |
gap: 0.5rem; |
| 134 |
|
- |
width: 100%; |
| 135 |
|
- |
margin-top: 2rem; |
| 136 |
|
- |
border-bottom: 1px solid #333; |
| 137 |
|
- |
padding-bottom: 1rem; |
| 138 |
|
- |
} |
|
107 |
+ |
Only add app-specific CSS when the shared sheet does not cover the pattern. When you do: |
| 139 |
108 |
|
|
| 140 |
|
- |
.logo { |
| 141 |
|
- |
font-size: 28px; |
| 142 |
|
- |
font-weight: 700; |
| 143 |
|
- |
text-decoration: none; |
| 144 |
|
- |
text-transform: uppercase; |
| 145 |
|
- |
} |
| 146 |
|
- |
``` |
| 147 |
|
- |
|
| 148 |
|
- |
## Navigation Links |
| 149 |
|
- |
|
| 150 |
|
- |
Compact gap, small font: |
| 151 |
|
- |
|
| 152 |
|
- |
```css |
| 153 |
|
- |
.links { |
| 154 |
|
- |
display: flex; |
| 155 |
|
- |
align-items: center; |
| 156 |
|
- |
gap: 0.75rem; |
| 157 |
|
- |
font-size: 12px; |
| 158 |
|
- |
} |
| 159 |
|
- |
``` |
| 160 |
|
- |
|
| 161 |
|
- |
## Interactive Elements |
| 162 |
|
- |
|
| 163 |
|
- |
All inputs, textareas, and buttons match the background — they blend into the surface with only a white border. **No border-radius**, padding uses `0.4rem 0.75rem`: |
| 164 |
|
- |
|
| 165 |
|
- |
```css |
| 166 |
|
- |
input, textarea { |
| 167 |
|
- |
background: #121113; |
| 168 |
|
- |
color: #ffffff; |
| 169 |
|
- |
border: 1px solid white; |
| 170 |
|
- |
padding: 0.4rem 0.75rem; |
| 171 |
|
- |
font-size: 14px; |
| 172 |
|
- |
width: 100%; |
| 173 |
|
- |
border-radius: 0; |
| 174 |
|
- |
} |
| 175 |
|
- |
|
| 176 |
|
- |
textarea { |
| 177 |
|
- |
min-height: 400px; |
| 178 |
|
- |
resize: vertical; |
| 179 |
|
- |
} |
| 180 |
|
- |
|
| 181 |
|
- |
button { |
| 182 |
|
- |
background: #121113; |
| 183 |
|
- |
color: #ffffff; |
| 184 |
|
- |
padding: 0.4rem 0.75rem; |
| 185 |
|
- |
border: 1px solid white; |
| 186 |
|
- |
cursor: pointer; |
| 187 |
|
- |
width: fit-content; |
| 188 |
|
- |
font-size: 14px; |
| 189 |
|
- |
border-radius: 0; |
| 190 |
|
- |
} |
| 191 |
|
- |
|
| 192 |
|
- |
button:hover, a:hover { |
| 193 |
|
- |
opacity: 0.7; |
| 194 |
|
- |
} |
| 195 |
|
- |
|
| 196 |
|
- |
a { |
| 197 |
|
- |
color: #ffffff; |
| 198 |
|
- |
text-decoration: none; |
| 199 |
|
- |
} |
| 200 |
|
- |
``` |
| 201 |
|
- |
|
| 202 |
|
- |
## Labels |
| 203 |
|
- |
|
| 204 |
|
- |
```css |
| 205 |
|
- |
label { |
| 206 |
|
- |
font-size: 12px; |
| 207 |
|
- |
opacity: 0.7; |
| 208 |
|
- |
} |
| 209 |
|
- |
``` |
| 210 |
|
- |
|
| 211 |
|
- |
## Errors |
| 212 |
|
- |
|
| 213 |
|
- |
Use a left border accent, not a full box border: |
| 214 |
|
- |
|
| 215 |
|
- |
```css |
| 216 |
|
- |
.error { |
| 217 |
|
- |
color: #ffffff; |
| 218 |
|
- |
border-left: 2px solid #ffffff; |
| 219 |
|
- |
padding-left: 0.5rem; |
| 220 |
|
- |
font-size: 13px; |
| 221 |
|
- |
opacity: 0.8; |
| 222 |
|
- |
} |
| 223 |
|
- |
``` |
| 224 |
|
- |
|
| 225 |
|
- |
## List Items |
| 226 |
|
- |
|
| 227 |
|
- |
Vertical stacking with bottom borders as dividers, 16px title size: |
| 228 |
|
- |
|
| 229 |
|
- |
```css |
| 230 |
|
- |
.item-list { |
| 231 |
|
- |
display: flex; |
| 232 |
|
- |
flex-direction: column; |
| 233 |
|
- |
width: 100%; |
| 234 |
|
- |
} |
| 235 |
|
- |
|
| 236 |
|
- |
.item { |
| 237 |
|
- |
display: flex; |
| 238 |
|
- |
flex-direction: column; |
| 239 |
|
- |
gap: 0.25rem; |
| 240 |
|
- |
padding: 0.75rem 0; |
| 241 |
|
- |
border-bottom: 1px solid #333; |
| 242 |
|
- |
} |
| 243 |
|
- |
|
| 244 |
|
- |
.item:hover { |
| 245 |
|
- |
opacity: 0.7; |
| 246 |
|
- |
} |
| 247 |
|
- |
|
| 248 |
|
- |
.item-title { |
| 249 |
|
- |
font-size: 16px; |
| 250 |
|
- |
} |
| 251 |
|
- |
|
| 252 |
|
- |
.item-meta { |
| 253 |
|
- |
font-size: 12px; |
| 254 |
|
- |
opacity: 0.5; |
| 255 |
|
- |
} |
| 256 |
|
- |
``` |
| 257 |
|
- |
|
| 258 |
|
- |
## Table Headers |
| 259 |
|
- |
|
| 260 |
|
- |
Uppercase, dimmed, lightweight: |
| 261 |
|
- |
|
| 262 |
|
- |
```css |
| 263 |
|
- |
th { |
| 264 |
|
- |
opacity: 0.5; |
| 265 |
|
- |
font-weight: 400; |
| 266 |
|
- |
font-size: 12px; |
| 267 |
|
- |
text-transform: uppercase; |
| 268 |
|
- |
} |
| 269 |
|
- |
``` |
| 270 |
|
- |
|
| 271 |
|
- |
## Meta Tags |
| 272 |
|
- |
|
| 273 |
|
- |
Always include: |
| 274 |
|
- |
```html |
| 275 |
|
- |
<meta name="theme-color" content="#121113" /> |
| 276 |
|
- |
``` |
|
109 |
+ |
- Match the palette and opacity scale above |
|
110 |
+ |
- `border-radius: 0` everywhere |
|
111 |
+ |
- Keep selectors shallow and class-based |
|
112 |
+ |
- Prefer extending existing classes over inventing new ones |
| 277 |
113 |
|
|
| 278 |
114 |
|
## What NOT to Do |
| 279 |
115 |
|
|
| 280 |
|
- |
- No `border-radius` — keep all corners sharp (explicitly set `border-radius: 0` on inputs/buttons) |
|
116 |
+ |
- Do not copy Darkmatter CSS into an app's static assets — link the crate's `/assets/darkmatter.css` instead |
|
117 |
+ |
- No `border-radius` — keep all corners sharp |
| 281 |
118 |
|
- No box shadows or drop shadows |
| 282 |
119 |
|
- No color other than `#121113`, `#ffffff`, and the gray tones (`#1e1c1f`, `#333`, `#555`) |
| 283 |
120 |
|
- **No `color: #888`** — use `opacity` on white text for visual hierarchy instead |
| 284 |
|
- |
- No external font CDNs — fonts are self-hosted |
|
121 |
+ |
- No external font CDNs — fonts come from the crate |
| 285 |
122 |
|
- No utility frameworks (no Tailwind, no Bootstrap) |
| 286 |
123 |
|
- No decorative elements, icons, or emojis |