mirror of
https://github.com/Nexoniarz/Niveus.git
synced 2026-11-03 04:34:26 +00:00
Niveus: a tactile, adaptive interface language
Bevelled controls with light falling across them, fields as wells, solid windows, and glass kept for the chrome that floats over everything else. Warm graphite in dark, soft paper in light, one brand color driving both. Ships its own fonts (Instrument Sans, JetBrains Mono; OFL). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
23b8dd376d
51 changed files with 15664 additions and 0 deletions
182
niveus/themes/light.css
Normal file
182
niveus/themes/light.css
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/* ==========================================================================
|
||||
Niveus — Light appearance
|
||||
--------------------------------------------------------------------------
|
||||
Values for the light side of every semantic role. Nothing here is consumed
|
||||
by components directly; tokens/color.css resolves these through light-dark().
|
||||
|
||||
Almost nothing below is a literal color. Each role is *derived* from
|
||||
--nv-brand, so setting one value re-colours the entire system: the accent
|
||||
and its states, what text goes on top of it, how the status colors lean, and
|
||||
how much of the brand bleeds into the greys. See tokens/color.css for the
|
||||
inputs.
|
||||
|
||||
Light Niveus reads as soft paper and enamel on a warm grey desk: surfaces
|
||||
that hold content stay near-white, so documents never look yellowed; the
|
||||
canvas around them is a few steps warmer and darker, so a window sits *on*
|
||||
something. Raised controls are bevelled — a bright top edge, a soft shade
|
||||
along the bottom, light falling across the face — and shadows are warm,
|
||||
the color of shade on paper rather than of a grey filter.
|
||||
========================================================================== */
|
||||
|
||||
:root {
|
||||
/* Follow the environment unless the application states an appearance. */
|
||||
color-scheme: light dark;
|
||||
}
|
||||
|
||||
:root[data-theme="light"] {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
/* [data-nv-brand] re-derives the whole set for a subtree, so one region can
|
||||
carry a different brand without a second theme. */
|
||||
:root,
|
||||
[data-nv-brand] {
|
||||
/* --- Canvas and surfaces -----------------------------------------------
|
||||
Paper stays paper: the two surfaces that hold content are left untinted so
|
||||
text keeps its contrast. Everything the surfaces sit *in* picks up a trace
|
||||
of the brand, which is what stops an accent from looking stuck on. */
|
||||
--nv-light-background: color-mix(in oklab, #e8e5de, var(--nv-brand) var(--nv-brand-tint));
|
||||
--nv-light-background-subtle: color-mix(in oklab, #eeece6, var(--nv-brand) var(--nv-brand-tint));
|
||||
--nv-light-surface: #fbfbfa;
|
||||
--nv-light-surface-elevated: #f8f8f6;
|
||||
--nv-light-surface-inset: color-mix(in oklab, #e3e2dd, var(--nv-brand) var(--nv-brand-tint));
|
||||
--nv-light-surface-hover: color-mix(in oklab, #f1f0ec, var(--nv-brand) var(--nv-brand-tint));
|
||||
--nv-light-surface-active: color-mix(in oklab, #e8e5de, var(--nv-brand) var(--nv-brand-tint));
|
||||
--nv-light-scrim: rgb(28 24 18 / 0.34);
|
||||
|
||||
/* --- Text ---------------------------------------------------------------
|
||||
Primary text stays neutral — it carries the reading contrast. The quieter
|
||||
two lean towards the brand, where a tint reads as warmth rather than as a
|
||||
loss of legibility. */
|
||||
--nv-light-text-primary: var(--nv-palette-neutral-900);
|
||||
--nv-light-text-secondary: color-mix(in oklab, var(--nv-palette-neutral-600), var(--nv-brand) 8%);
|
||||
--nv-light-text-tertiary: color-mix(in oklab, var(--nv-palette-neutral-500), var(--nv-brand) 8%);
|
||||
--nv-light-text-disabled: var(--nv-palette-neutral-400);
|
||||
--nv-light-text-inverted: var(--nv-palette-neutral-0);
|
||||
|
||||
/* --- Borders ------------------------------------------------------------ */
|
||||
--nv-light-border-subtle: rgb(28 24 18 / 0.07);
|
||||
--nv-light-border: rgb(28 24 18 / 0.13);
|
||||
--nv-light-border-strong: rgb(28 24 18 / 0.22);
|
||||
|
||||
/* --- Accent --------------------------------------------------------------
|
||||
Every filled color is pushed away from the middle of the lightness range
|
||||
before it is used. A mid-tone is the one place where neither white nor
|
||||
black text reaches 4.5:1, so a brand that lands there is darkened until
|
||||
white works — or, if it is already light, lightened until black does. The
|
||||
brand's hue and chroma are untouched; only its lightness moves, and only
|
||||
as far as it has to. */
|
||||
--nv-light-accent: oklch(from var(--nv-brand) calc(
|
||||
clamp(0, (var(--nv-contrast-pivot) - l) * 100, 1) * min(l, var(--nv-contrast-dark)) +
|
||||
(1 - clamp(0, (var(--nv-contrast-pivot) - l) * 100, 1)) * max(l, var(--nv-contrast-light))
|
||||
) clamp(0.02, c, 0.25) h);
|
||||
--nv-light-accent-hover: oklch(from var(--nv-light-accent) calc(l - 0.045) c h);
|
||||
--nv-light-accent-active: oklch(from var(--nv-light-accent) calc(l - 0.09) c h);
|
||||
--nv-light-accent-subtle: oklch(from var(--nv-light-accent) 0.965 calc(c * 0.16) h);
|
||||
--nv-light-accent-subtle-hover: oklch(from var(--nv-light-accent) 0.93 calc(c * 0.22) h);
|
||||
--nv-light-accent-border: oklch(from var(--nv-light-accent) l c h / 0.32);
|
||||
--nv-light-accent-text: oklch(from var(--nv-light-accent) clamp(0.3, calc(l - 0.12), 0.5) c h);
|
||||
/* Text that lands on the color itself. The clamp is a step function: below
|
||||
the lightness threshold it resolves to 1 and the text goes near-white,
|
||||
above it to 0 and the text goes near-black — so a yellow brand gets dark
|
||||
labels and a navy one gets light labels, with no second token to set. */
|
||||
--nv-light-on-accent: oklch(from var(--nv-light-accent)
|
||||
calc(0.14 + clamp(0, (0.68 - l) * 100, 1) * 0.84)
|
||||
calc(c * 0.2) h);
|
||||
|
||||
/* --- Success ------------------------------------------------------------- */
|
||||
--nv-light-success: oklch(from
|
||||
color-mix(in oklab, var(--nv-palette-success-500), var(--nv-brand) var(--nv-brand-harmony))
|
||||
calc(
|
||||
clamp(0, (var(--nv-contrast-pivot) - l) * 100, 1) * min(l, var(--nv-contrast-dark)) +
|
||||
(1 - clamp(0, (var(--nv-contrast-pivot) - l) * 100, 1)) * max(l, var(--nv-contrast-light))
|
||||
) clamp(0.02, c, 0.25) h);
|
||||
--nv-light-success-hover: oklch(from var(--nv-light-success) calc(l - 0.05) c h);
|
||||
--nv-light-success-subtle: oklch(from var(--nv-light-success) 0.965 calc(c * 0.16) h);
|
||||
--nv-light-success-border: oklch(from var(--nv-light-success) l c h / 0.3);
|
||||
--nv-light-success-text: oklch(from var(--nv-light-success) clamp(0.3, calc(l - 0.1), 0.48) c h);
|
||||
--nv-light-on-success: oklch(from var(--nv-light-success)
|
||||
calc(0.14 + clamp(0, (0.68 - l) * 100, 1) * 0.84)
|
||||
calc(c * 0.2) h);
|
||||
|
||||
/* --- Warning -------------------------------------------------------------- */
|
||||
/* Amber starts above the pivot on purpose. Pushed the other way it lands as
|
||||
brown, which reads as neither a warning nor a color anyone chose. */
|
||||
--nv-light-warning: oklch(from
|
||||
color-mix(in oklab, var(--nv-palette-warning-400), var(--nv-brand) var(--nv-brand-harmony))
|
||||
calc(
|
||||
clamp(0, (var(--nv-contrast-pivot) - l) * 100, 1) * min(l, var(--nv-contrast-dark)) +
|
||||
(1 - clamp(0, (var(--nv-contrast-pivot) - l) * 100, 1)) * max(l, var(--nv-contrast-light))
|
||||
) clamp(0.02, c, 0.25) h);
|
||||
--nv-light-warning-hover: oklch(from var(--nv-light-warning) calc(l - 0.05) c h);
|
||||
--nv-light-warning-subtle: oklch(from var(--nv-light-warning) 0.965 calc(c * 0.16) h);
|
||||
--nv-light-warning-border: oklch(from var(--nv-light-warning) l c h / 0.32);
|
||||
--nv-light-warning-text: oklch(from var(--nv-light-warning) clamp(0.3, calc(l - 0.1), 0.48) c h);
|
||||
--nv-light-on-warning: oklch(from var(--nv-light-warning)
|
||||
calc(0.14 + clamp(0, (0.68 - l) * 100, 1) * 0.84)
|
||||
calc(c * 0.2) h);
|
||||
|
||||
/* --- Danger ---------------------------------------------------------------- */
|
||||
--nv-light-danger: oklch(from
|
||||
color-mix(in oklab, var(--nv-palette-danger-500), var(--nv-brand) var(--nv-brand-harmony))
|
||||
calc(
|
||||
clamp(0, (var(--nv-contrast-pivot) - l) * 100, 1) * min(l, var(--nv-contrast-dark)) +
|
||||
(1 - clamp(0, (var(--nv-contrast-pivot) - l) * 100, 1)) * max(l, var(--nv-contrast-light))
|
||||
) clamp(0.02, c, 0.25) h);
|
||||
--nv-light-danger-hover: oklch(from var(--nv-light-danger) calc(l - 0.05) c h);
|
||||
--nv-light-danger-active: oklch(from var(--nv-light-danger) calc(l - 0.1) c h);
|
||||
--nv-light-danger-subtle: oklch(from var(--nv-light-danger) 0.965 calc(c * 0.16) h);
|
||||
--nv-light-danger-border: oklch(from var(--nv-light-danger) l c h / 0.3);
|
||||
--nv-light-danger-text: oklch(from var(--nv-light-danger) clamp(0.3, calc(l - 0.1), 0.48) c h);
|
||||
--nv-light-on-danger: oklch(from var(--nv-light-danger)
|
||||
calc(0.14 + clamp(0, (0.68 - l) * 100, 1) * 0.84)
|
||||
calc(c * 0.2) h);
|
||||
|
||||
/* --- Depth and material -------------------------------------------------
|
||||
Three shadow colors build every elevation level: an ambient contact
|
||||
shadow, a soft penumbra, and a deeper umbra for high elevations. */
|
||||
--nv-light-shadow-ambient: rgb(40 32 20 / 0.09);
|
||||
--nv-light-shadow-penumbra: rgb(40 32 20 / 0.12);
|
||||
--nv-light-shadow-umbra: rgb(40 32 20 / 0.11);
|
||||
--nv-light-shadow-inset: rgb(40 32 20 / 0.17);
|
||||
--nv-light-highlight: rgb(255 255 255 / 0.9);
|
||||
--nv-light-highlight-strong: rgb(255 255 255 / 1);
|
||||
|
||||
/* Paper already has a border doing the contact work, so the outline only
|
||||
softens it; the bottom shade is faint for the same reason. */
|
||||
--nv-light-lowlight: rgb(40 32 20 / 0.07);
|
||||
--nv-light-outline: rgb(40 32 20 / 0.05);
|
||||
|
||||
--nv-light-sheen-top: rgb(255 255 255 / 0.75);
|
||||
--nv-light-sheen-bottom: rgb(40 32 20 / 0.04);
|
||||
--nv-light-sheen-strong-top: rgb(255 255 255 / 0.24);
|
||||
--nv-light-sheen-strong-bottom: rgb(20 16 10 / 0.1);
|
||||
|
||||
--nv-light-knob: var(--nv-palette-neutral-0);
|
||||
--nv-light-knob-shade: rgb(40 32 20 / 0.13);
|
||||
|
||||
/* Light surfaces are already lighter than their canvas; the shadow alone
|
||||
carries elevation, so there is nothing to add. */
|
||||
--nv-light-elevation-tint-1: transparent;
|
||||
--nv-light-elevation-tint-2: transparent;
|
||||
--nv-light-elevation-tint-3: transparent;
|
||||
--nv-light-elevation-tint-4: transparent;
|
||||
--nv-light-elevation-tint-5: transparent;
|
||||
|
||||
--nv-light-material-frosted: rgb(251 251 249 / 0.66);
|
||||
--nv-light-material-glass: rgb(251 251 249 / 0.5);
|
||||
--nv-light-material-border: rgb(255 255 255 / 0.6);
|
||||
|
||||
/* --- Window controls --------------------------------------------------------- */
|
||||
--nv-light-window-close: var(--nv-palette-window-close);
|
||||
--nv-light-window-minimize: var(--nv-palette-window-minimize);
|
||||
--nv-light-window-zoom: var(--nv-palette-window-zoom);
|
||||
--nv-light-window-inactive: var(--nv-palette-neutral-300);
|
||||
--nv-light-window-control-ring: rgb(0 0 0 / 0.16);
|
||||
--nv-light-window-glyph: rgb(0 0 0 / 0.55);
|
||||
|
||||
/* --- Interaction ----------------------------------------------------------- */
|
||||
--nv-light-focus-ring: oklch(from var(--nv-light-accent) l c h / 0.4);
|
||||
--nv-light-focus-ring-contrast: rgb(255 255 255 / 0.9);
|
||||
--nv-light-selection: oklch(from var(--nv-light-accent) l c h / 0.2);
|
||||
}
|
||||
Loading…
Reference in a new issue