feat(ui): warm light theme and pre-mixed status fills
- Light mode moves to Claude's ivory/terracotta family: page #e8e5da, cards #f5f3ec (a notch below Claude's ivory, no pure-white step), warm borders and card shadow; dark mode is untouched. - The surface ramp rises in lightness with its index in BOTH themes, so a card sits brighter than the page and every hover lifts instead of dims. - Light --accent #a34a28 (the brand #cc785c is 3.1:1 on ivory); --fg-muted held at >=4.5:1; new --syn-* syntax tokens, dark keeps its pastels. - Status/accent fills (bg-*/N, border-*/N) compile to color-mix against --tint-base instead of rgb(/a), so a chip is one colour on every surface. - Hardcoded dark-only hovers (hover:text-white, hover:bg-white/5) replaced by tokens in DateTimePicker and SessionDrillIn.
This commit is contained in:
+89
-23
@@ -15,7 +15,10 @@
|
||||
* 1-2 app/chrome background 6-8 borders (6 subtle, 7-8 stronger)
|
||||
* 3-5 component background 9-10 solid (buttons, vibrant fills)
|
||||
* 11-12 text (11 secondary, 12 primary)
|
||||
* `slate` supplies surface/border/fg here; `blue` supplies accent; `green`/
|
||||
* The DARK theme follows it literally: `slate` supplies surface/border/fg and
|
||||
* `blue` supplies accent. The LIGHT theme keeps the structure (same roles, same
|
||||
* rising-lightness ramp) but swaps the hue family for Claude's own warm ivory
|
||||
* and terracotta, because a cool near-white page reads as glare. `green`/
|
||||
* `red`/`amber` step 11 supplies the status tokens — the same step used for
|
||||
* fg-secondary, since 11 is Radix's guaranteed-readable-text step. Values are
|
||||
* the literal Radix hex constants (steps 1/2/3/4/5/6/7/9/11/12), converted to
|
||||
@@ -23,27 +26,70 @@
|
||||
*/
|
||||
:root {
|
||||
/* Light theme — the CSS default, so it applies with no class on <html>.
|
||||
Radix `slate` (light), steps 1/2/3/4/5/6/7. */
|
||||
--surface-0: 252 252 253; /* slate-1 #fcfcfd */
|
||||
--surface-1: 249 249 251; /* slate-2 #f9f9fb */
|
||||
--surface-2: 240 240 243; /* slate-3 #f0f0f3 */
|
||||
--surface-3: 232 232 236; /* slate-4 #e8e8ec */
|
||||
--surface-4: 224 225 230; /* slate-5 #e0e1e6 */
|
||||
--surface-5: 217 217 224; /* slate-6 #d9d9e0 */
|
||||
--border: 217 217 224; /* slate-6 #d9d9e0 */
|
||||
--border-light: 205 206 214; /* slate-7 #cdced6 */
|
||||
--accent: 0 144 255; /* blue-9 #0090ff */
|
||||
--accent-hover: 5 136 240; /* blue-10 #0588f0 */
|
||||
--fg-primary: 28 32 36; /* slate-12 #1c2024 */
|
||||
--fg-secondary: 96 100 108; /* slate-11 #60646c */
|
||||
--fg-muted: 139 141 152; /* slate-9 #8b8d98 */
|
||||
--shadow-card: 0 1px 2px rgb(15 23 42 / 0.06), 0 1px 3px rgb(15 23 42 / 0.08);
|
||||
/* Status: green/red/amber step 11 (light) — the same "readable text" step
|
||||
as fg-secondary, so success/danger/warning sit at the same visual weight
|
||||
as ordinary secondary text, not shouting over it. */
|
||||
--status-success: 33 131 88; /* green-11 #218358 */
|
||||
--status-danger: 206 44 49; /* red-11 #ce2c31 */
|
||||
--status-warning: 171 100 0; /* amber-11 #ab6400 */
|
||||
Radix `slate` light, RE-ORDERED so lightness rises with the index exactly
|
||||
as it does in dark: the page is the DARKEST step and a card is brighter
|
||||
than the page it sits on. The previous light block used the scale in its
|
||||
native direction, which inverted the whole language — a near-white page
|
||||
(glare) under grey cards that read as recessed, and every `hover:bg-*`
|
||||
darkening instead of lifting.
|
||||
|
||||
The HUE is warm — Claude's own ivory/terracotta family, not a cool slate.
|
||||
A cool near-white ramp kept reading as glare no matter how far the page
|
||||
step was pulled down, because the brightest thing on screen was also the
|
||||
bluest. Cream lowers the perceived glare at the same measured lightness
|
||||
and gives every neutral a warm cast to sit against. The whole ramp sits
|
||||
one notch below Claude's own ivory (#faf9f5 card) and no step reaches pure
|
||||
white: at full brightness a large light panel still tires the eye. */
|
||||
--surface-0: 232 229 218; /* #e8e5da — page background */
|
||||
--surface-1: 236 233 223; /* #ece9df — sub-headers inside a card */
|
||||
--surface-2: 240 237 228; /* #f0ede4 — inputs, chips, toolbars */
|
||||
--surface-3: 245 243 236; /* #f5f3ec — `.card`, Claude's ivory a step down */
|
||||
--surface-4: 249 247 241; /* #f9f7f1 — hover / active lift */
|
||||
--surface-5: 252 251 247; /* #fcfbf7 — topmost, rare */
|
||||
--border: 207 201 184; /* #cfc9b8 */
|
||||
--border-light: 222 217 204; /* #ded9cc */
|
||||
/* Claude's terracotta (#cc785c), taken down two steps: the brand value is
|
||||
3.1:1 on ivory and 3.3:1 under white text, so it works as a large fill and
|
||||
fails as a link or a button label. This is 5.3:1 as text on a card and
|
||||
5.9:1 white-on-accent. Dark mode keeps its blue — inverting a warm accent
|
||||
onto a near-black page is a different problem with a different answer. */
|
||||
--accent: 163 74 40; /* #a34a28 */
|
||||
--accent-hover: 142 63 32; /* #8e3f20 */
|
||||
--fg-primary: 31 30 27; /* #1f1e1b — 15.0:1 on a card */
|
||||
--fg-secondary: 96 91 83; /* #605b53 — 6.1:1 */
|
||||
/* Measured, not eyeballed: this carries real content (timestamps, counts),
|
||||
so it is held above 4.5:1 — 5.4:1 on a card, 4.7:1 on the page — and still
|
||||
sits a clear step below fg-secondary. */
|
||||
--fg-muted: 104 99 89; /* #686359 */
|
||||
/* Warm and soft, to match the surfaces: a neutral-grey shadow goes muddy
|
||||
over cream. The SHADOW carries "raised" here, not the quiet border. */
|
||||
--shadow-card: 0 1px 2px rgb(60 50 30 / 0.05), 0 2px 6px rgb(60 50 30 / 0.07);
|
||||
/* Status: darkened two steps from Radix 11. One step cleared 4.5:1 against
|
||||
the card; these also clear it against the status's OWN densest chip (a
|
||||
20% tint of itself — 4.5:1), which is where the label actually sits. */
|
||||
--status-success: 22 104 66; /* #166842 */
|
||||
--status-danger: 170 36 41; /* #aa2429 */
|
||||
--status-warning: 133 79 0; /* #854f00 */
|
||||
/* What every status/accent FILL is pre-mixed against (see `tint()` in
|
||||
tailwind.config.js) — the card surface, because that is where chips and
|
||||
alert strips overwhelmingly sit. */
|
||||
--tint-base: 245 243 236; /* = surface-3 */
|
||||
/* Syntax colours for `lib/highlight.ts`. Same hues as the dark set, taken
|
||||
four steps down the Tailwind ramp (300 → 700): a pastel keyword is legible
|
||||
on a near-black code block and invisible on a light one. */
|
||||
--syn-comment: 107 114 128; /* gray-500 #6b7280 */
|
||||
--syn-string: 4 120 87; /* emerald-700 #047857 */
|
||||
--syn-number: 194 65 12; /* orange-700 #c2410c */
|
||||
--syn-keyword: 109 40 217; /* violet-700 #6d28d9 */
|
||||
--syn-builtin: 3 105 161; /* sky-700 #0369a1 */
|
||||
--syn-function: 180 83 9; /* amber-700 #b45309 */
|
||||
--syn-operator: 190 24 93; /* pink-700 #be185d */
|
||||
--syn-punctuation: 107 114 128; /* gray-500 #6b7280 */
|
||||
--syn-property: 14 116 144; /* cyan-700 #0e7490 */
|
||||
--syn-tag: 190 18 60; /* rose-700 #be123c */
|
||||
--syn-plain: 31 30 27; /* = fg-primary */
|
||||
--syn-add: 4 120 87; /* emerald-700 */
|
||||
--syn-del: 185 28 28; /* red-700 #b91c1c */
|
||||
}
|
||||
|
||||
.dark {
|
||||
@@ -70,6 +116,21 @@
|
||||
--status-success: 61 214 140; /* green-11 dark #3dd68c */
|
||||
--status-danger: 255 149 146; /* red-11 dark #ff9592 */
|
||||
--status-warning: 255 202 22; /* amber-11 dark #ffca16 */
|
||||
--tint-base: 39 42 45; /* = surface-3 */
|
||||
/* Unchanged from the pastels this file has always drawn code in. */
|
||||
--syn-comment: 107 114 128; /* gray-500 #6b7280 */
|
||||
--syn-string: 110 231 183; /* emerald-300 #6ee7b7 */
|
||||
--syn-number: 253 186 116; /* orange-300 #fdba74 */
|
||||
--syn-keyword: 196 181 253; /* violet-300 #c4b5fd */
|
||||
--syn-builtin: 125 211 252; /* sky-300 #7dd3fc */
|
||||
--syn-function: 254 240 138; /* yellow-200 #fef08a */
|
||||
--syn-operator: 249 168 212; /* pink-300 #f9a8d4 */
|
||||
--syn-punctuation: 156 163 175; /* gray-400 #9ca3af */
|
||||
--syn-property: 103 232 249; /* cyan-300 #67e8f9 */
|
||||
--syn-tag: 253 164 175; /* rose-300 #fda4af */
|
||||
--syn-plain: 229 231 235; /* gray-200 #e5e7eb */
|
||||
--syn-add: 110 231 183; /* emerald-300 */
|
||||
--syn-del: 252 165 165; /* red-300 #fca5a5 */
|
||||
}
|
||||
|
||||
@layer base {
|
||||
@@ -102,12 +163,17 @@
|
||||
}
|
||||
|
||||
::-webkit-calendar-picker-indicator {
|
||||
filter: invert(1) brightness(0.8);
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
/* The browser draws this glyph near-black. Inverting it is a DARK-mode fix;
|
||||
applied globally it painted a white icon onto a white field. */
|
||||
.dark ::-webkit-calendar-picker-indicator {
|
||||
filter: invert(1) brightness(0.8);
|
||||
}
|
||||
|
||||
::-webkit-calendar-picker-indicator:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user