Depth, light and translucency without changing the API

Niveus read flat: thin sheens, short shadows, opaque grey chrome and a
painted canvas. This retunes values and component internals only; every
class and token name is unchanged, so existing pages pick it up as is.

- Canvas: a faint accent light falls across the page, so translucent
  layers have something to show through.
- Surfaces: the surface sheen runs the full height (lit top, shaded
  foot); raised and filled sheens, highlights and bevels are stronger;
  the elevation scale is deeper and softer.
- Translucency: cards, dialogs, the sidebar and tab tracks let some of
  the canvas through, with blur so busy grounds never read as texture;
  frosted and glass materials are clearer with more blur.
- Filled buttons give off a soft glow of their own color.
- Light fields are paper instead of grey wells that looked disabled.
- Fixes: navigation bars wrap and lists scroll inside them instead of
  overflowing the page on phones; choice labels sit at control size;
  disabled ghost buttons no longer grow a filled well; the color-swatch
  rule is split so neither engine drops it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019iMUTHrD8K9CSuHqsanje9
This commit is contained in:
Claude 2026-10-12 20:49:22 +00:00
commit a19e0f205f
No known key found for this signature in database
13 changed files with 281 additions and 139 deletions

209
dist/niveus.css vendored
View file

@ -525,34 +525,35 @@
--nv-elevation-1: --nv-elevation-1:
0 1px 1px var(--nv-color-shadow-ambient), 0 1px 1px var(--nv-color-shadow-ambient),
0 1px 3px -1px var(--nv-color-shadow-penumbra); 0 2px 4px -1px var(--nv-color-shadow-penumbra),
0 6px 14px -8px var(--nv-color-shadow-umbra);
--nv-elevation-2: --nv-elevation-2:
0 1px 1px var(--nv-color-shadow-ambient), 0 1px 1px var(--nv-color-shadow-ambient),
0 2px 4px -1px var(--nv-color-shadow-penumbra), 0 3px 6px -2px var(--nv-color-shadow-penumbra),
0 4px 8px -4px var(--nv-color-shadow-umbra); 0 10px 20px -10px var(--nv-color-shadow-umbra);
--nv-elevation-3: --nv-elevation-3:
0 1px 1px var(--nv-color-shadow-ambient), 0 1px 2px var(--nv-color-shadow-ambient),
0 4px 8px -2px var(--nv-color-shadow-penumbra), 0 6px 12px -4px var(--nv-color-shadow-penumbra),
0 10px 20px -6px var(--nv-color-shadow-umbra); 0 18px 36px -12px var(--nv-color-shadow-umbra);
--nv-elevation-4: --nv-elevation-4:
0 1px 2px var(--nv-color-shadow-ambient), 0 1px 2px var(--nv-color-shadow-ambient),
0 8px 16px -4px var(--nv-color-shadow-penumbra), 0 10px 20px -6px var(--nv-color-shadow-penumbra),
0 20px 40px -10px var(--nv-color-shadow-umbra); 0 30px 60px -16px var(--nv-color-shadow-umbra);
--nv-elevation-5: --nv-elevation-5:
0 1px 2px var(--nv-color-shadow-ambient), 0 2px 3px var(--nv-color-shadow-ambient),
0 14px 28px -6px var(--nv-color-shadow-penumbra), 0 16px 32px -8px var(--nv-color-shadow-penumbra),
0 32px 64px -14px var(--nv-color-shadow-umbra); 0 44px 88px -20px var(--nv-color-shadow-umbra);
/* --- Inset --------------------------------------------------------------- /* --- Inset ---------------------------------------------------------------
Recessed surfaces: fields, wells, tracks, pressed controls. */ Recessed surfaces: fields, wells, tracks, pressed controls. */
--nv-elevation-inset-sm: inset 0 1px 2px var(--nv-color-shadow-inset); --nv-elevation-inset-sm: inset 0 1px 2px var(--nv-color-shadow-inset);
--nv-elevation-inset-md: --nv-elevation-inset-md:
inset 0 1px 1px var(--nv-color-shadow-inset), inset 0 1px 1px var(--nv-color-shadow-inset),
inset 0 2px 5px -1px var(--nv-color-shadow-inset); inset 0 3px 6px -2px var(--nv-color-shadow-inset);
--nv-elevation-inset-lg: --nv-elevation-inset-lg:
inset 0 2px 3px var(--nv-color-shadow-inset), inset 0 2px 3px var(--nv-color-shadow-inset),
inset 0 6px 12px -3px var(--nv-color-shadow-inset); inset 0 6px 12px -3px var(--nv-color-shadow-inset);
@ -738,30 +739,31 @@
:root { :root {
/* --- Blur ---------------------------------------------------------------- */ /* --- Blur ---------------------------------------------------------------- */
--nv-blur-sm: 8px; --nv-blur-sm: 12px;
--nv-blur-md: 16px; --nv-blur-md: 24px;
--nv-blur-lg: 28px; --nv-blur-lg: 36px;
--nv-blur-xl: 44px; --nv-blur-xl: 56px;
/* Backdrops lose saturation when blurred; a touch of saturate() puts the /* Backdrops lose saturation when blurred; a touch of saturate() puts the
color back so frosted surfaces do not read as gray films. Moderate on color back so frosted surfaces do not read as gray films. Moderate on
purpose: the blur says "this floats", it is not the look itself. */ purpose: the blur says "this floats", it is not the look itself. */
--nv-backdrop-saturate: 160%; --nv-backdrop-saturate: 180%;
--nv-backdrop-frosted: blur(var(--nv-blur-md)) saturate(var(--nv-backdrop-saturate)); --nv-backdrop-frosted: blur(var(--nv-blur-md)) saturate(var(--nv-backdrop-saturate));
--nv-backdrop-glass: blur(var(--nv-blur-sm)) saturate(var(--nv-backdrop-saturate)); --nv-backdrop-glass: blur(var(--nv-blur-sm)) saturate(var(--nv-backdrop-saturate));
/* --- Sheen ------------------------------------------------------------------ /* --- Sheen ------------------------------------------------------------------
raised neutral controls: buttons, the selected tab, a titlebar raised neutral controls: buttons, the selected tab, a titlebar
filled saturated fills: primary and danger buttons, checked marks filled saturated fills: primary and danger buttons, checked marks
surface large surfaces: windows, dialogs, cards. The light fades out surface large surfaces: windows, dialogs, cards. Brightest along the
within the first stretch, so it reads as a lit top edge top edge, easing through the middle and settling into a faint
rather than as a gradient over the content. shade at the foot, so a panel reads as a curved, lit body
rather than as a flat sheet.
knob a round thumb: lit from above, shaded towards its rim */ knob a round thumb: lit from above, shaded towards its rim */
--nv-sheen-raised: linear-gradient(var(--nv-color-sheen-top), var(--nv-color-sheen-bottom)); --nv-sheen-raised: linear-gradient(var(--nv-color-sheen-top), var(--nv-color-sheen-bottom));
--nv-sheen-filled: linear-gradient(var(--nv-color-sheen-strong-top), var(--nv-color-sheen-strong-bottom)); --nv-sheen-filled: linear-gradient(var(--nv-color-sheen-strong-top), var(--nv-color-sheen-strong-bottom));
--nv-sheen-surface: linear-gradient(var(--nv-color-sheen-top), transparent 6rem); --nv-sheen-surface: linear-gradient(var(--nv-color-sheen-top), transparent 7rem, transparent 55%, var(--nv-color-sheen-bottom));
--nv-sheen-knob: radial-gradient(circle at 50% 30%, transparent 35%, var(--nv-color-knob-shade)); --nv-sheen-knob: radial-gradient(circle at 50% 22%, var(--nv-color-highlight-strong), transparent 45%), radial-gradient(circle at 50% 30%, transparent 40%, var(--nv-color-knob-shade));
--nv-backdrop-scrim: blur(var(--nv-blur-sm)) saturate(120%); --nv-backdrop-scrim: blur(var(--nv-blur-sm)) saturate(140%);
/* --- Material recipes ----------------------------------------------------- /* --- Material recipes -----------------------------------------------------
Each recipe is the full set of properties that defines the material. Each recipe is the full set of properties that defines the material.
@ -851,7 +853,7 @@
--nv-light-background-subtle: color-mix(in oklab, #eeece6, 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: #fbfbfa;
--nv-light-surface-elevated: #f8f8f6; --nv-light-surface-elevated: #f8f8f6;
--nv-light-surface-inset: color-mix(in oklab, #e3e2dd, var(--nv-brand) var(--nv-brand-tint)); --nv-light-surface-inset: color-mix(in oklab, #eeede8, 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-hover: color-mix(in oklab, #f1f0ec, var(--nv-brand) var(--nv-brand-tint));
--nv-light-surface-active: color-mix(in oklab, #e6e5e0, var(--nv-brand) var(--nv-brand-tint)); --nv-light-surface-active: color-mix(in oklab, #e6e5e0, var(--nv-brand) var(--nv-brand-tint));
--nv-light-scrim: rgb(28 24 18 / 0.34); --nv-light-scrim: rgb(28 24 18 / 0.34);
@ -947,22 +949,22 @@
/* --- Depth and material ------------------------------------------------- /* --- Depth and material -------------------------------------------------
Three shadow colors build every elevation level: an ambient contact Three shadow colors build every elevation level: an ambient contact
shadow, a soft penumbra, and a deeper umbra for high elevations. */ shadow, a soft penumbra, and a deeper umbra for high elevations. */
--nv-light-shadow-ambient: rgb(40 32 20 / 0.09); --nv-light-shadow-ambient: rgb(40 32 20 / 0.08);
--nv-light-shadow-penumbra: rgb(40 32 20 / 0.12); --nv-light-shadow-penumbra: rgb(40 32 20 / 0.1);
--nv-light-shadow-umbra: rgb(40 32 20 / 0.11); --nv-light-shadow-umbra: rgb(40 32 20 / 0.16);
--nv-light-shadow-inset: rgb(40 32 20 / 0.17); --nv-light-shadow-inset: rgb(40 32 20 / 0.14);
--nv-light-highlight: rgb(255 255 255 / 0.9); --nv-light-highlight: rgb(255 255 255 / 0.9);
--nv-light-highlight-strong: rgb(255 255 255 / 1); --nv-light-highlight-strong: rgb(255 255 255 / 1);
/* Paper already has a border doing the contact work, so the outline only /* Paper already has a border doing the contact work, so the outline only
softens it; the bottom shade is faint for the same reason. */ softens it; the bottom shade is faint for the same reason. */
--nv-light-lowlight: rgb(40 32 20 / 0.07); --nv-light-lowlight: rgb(40 32 20 / 0.09);
--nv-light-outline: rgb(40 32 20 / 0.05); --nv-light-outline: rgb(40 32 20 / 0.05);
--nv-light-sheen-top: rgb(255 255 255 / 0.75); --nv-light-sheen-top: rgb(255 255 255 / 0.9);
--nv-light-sheen-bottom: rgb(40 32 20 / 0.04); --nv-light-sheen-bottom: rgb(40 32 20 / 0.07);
--nv-light-sheen-strong-top: rgb(255 255 255 / 0.24); --nv-light-sheen-strong-top: rgb(255 255 255 / 0.32);
--nv-light-sheen-strong-bottom: rgb(20 16 10 / 0.1); --nv-light-sheen-strong-bottom: rgb(20 16 10 / 0.16);
--nv-light-knob: var(--nv-palette-neutral-0); --nv-light-knob: var(--nv-palette-neutral-0);
--nv-light-knob-shade: rgb(40 32 20 / 0.13); --nv-light-knob-shade: rgb(40 32 20 / 0.13);
@ -975,9 +977,9 @@
--nv-light-elevation-tint-4: transparent; --nv-light-elevation-tint-4: transparent;
--nv-light-elevation-tint-5: transparent; --nv-light-elevation-tint-5: transparent;
--nv-light-material-frosted: rgb(251 251 249 / 0.66); --nv-light-material-frosted: rgb(252 252 250 / 0.56);
--nv-light-material-glass: rgb(251 251 249 / 0.5); --nv-light-material-glass: rgb(252 252 250 / 0.4);
--nv-light-material-border: rgb(255 255 255 / 0.6); --nv-light-material-border: rgb(255 255 255 / 0.72);
/* --- Window controls --------------------------------------------------------- */ /* --- Window controls --------------------------------------------------------- */
--nv-light-window-close: var(--nv-palette-window-close); --nv-light-window-close: var(--nv-palette-window-close);
@ -1017,7 +1019,7 @@
:root, :root,
[data-nv-brand] { [data-nv-brand] {
/* --- Canvas and surfaces ----------------------------------------------- */ /* --- Canvas and surfaces ----------------------------------------------- */
--nv-dark-background: color-mix(in oklab, #121214, var(--nv-brand) var(--nv-brand-tint)); --nv-dark-background: color-mix(in oklab, #0f0f12, var(--nv-brand) var(--nv-brand-tint));
--nv-dark-background-subtle: color-mix(in oklab, #18181b, var(--nv-brand) var(--nv-brand-tint)); --nv-dark-background-subtle: color-mix(in oklab, #18181b, var(--nv-brand) var(--nv-brand-tint));
--nv-dark-surface: color-mix(in oklab, #1f1f22, var(--nv-brand) var(--nv-brand-tint)); --nv-dark-surface: color-mix(in oklab, #1f1f22, var(--nv-brand) var(--nv-brand-tint));
--nv-dark-surface-elevated: color-mix(in oklab, #2a2a2e, var(--nv-brand) var(--nv-brand-tint)); --nv-dark-surface-elevated: color-mix(in oklab, #2a2a2e, var(--nv-brand) var(--nv-brand-tint));
@ -1111,33 +1113,33 @@
--nv-dark-shadow-penumbra: rgb(0 0 0 / 0.5); --nv-dark-shadow-penumbra: rgb(0 0 0 / 0.5);
--nv-dark-shadow-umbra: rgb(0 0 0 / 0.55); --nv-dark-shadow-umbra: rgb(0 0 0 / 0.55);
--nv-dark-shadow-inset: rgb(0 0 0 / 0.65); --nv-dark-shadow-inset: rgb(0 0 0 / 0.65);
--nv-dark-highlight: rgb(255 255 255 / 0.11); --nv-dark-highlight: rgb(255 255 255 / 0.15);
--nv-dark-highlight-strong: rgb(255 255 255 / 0.17); --nv-dark-highlight-strong: rgb(255 255 255 / 0.24);
/* The contact line is what separates graphite from graphite: a raised /* The contact line is what separates graphite from graphite: a raised
surface over a dark canvas has no shadow to show, but it always has an surface over a dark canvas has no shadow to show, but it always has an
edge. */ edge. */
--nv-dark-lowlight: rgb(0 0 0 / 0.42); --nv-dark-lowlight: rgb(0 0 0 / 0.5);
--nv-dark-outline: rgb(0 0 0 / 0.72); --nv-dark-outline: rgb(0 0 0 / 0.72);
--nv-dark-sheen-top: rgb(255 255 255 / 0.06); --nv-dark-sheen-top: rgb(255 255 255 / 0.09);
--nv-dark-sheen-bottom: rgb(0 0 0 / 0.09); --nv-dark-sheen-bottom: rgb(0 0 0 / 0.18);
--nv-dark-sheen-strong-top: rgb(255 255 255 / 0.2); --nv-dark-sheen-strong-top: rgb(255 255 255 / 0.3);
--nv-dark-sheen-strong-bottom: rgb(0 0 0 / 0.12); --nv-dark-sheen-strong-bottom: rgb(0 0 0 / 0.2);
--nv-dark-knob: #f4f3ef; --nv-dark-knob: #f4f3ef;
--nv-dark-knob-shade: rgb(40 32 20 / 0.24); --nv-dark-knob-shade: rgb(40 32 20 / 0.3);
/* The higher a surface sits, the more light reaches it. */ /* The higher a surface sits, the more light reaches it. */
--nv-dark-elevation-tint-1: rgb(255 255 255 / 0.025); --nv-dark-elevation-tint-1: rgb(255 255 255 / 0.03);
--nv-dark-elevation-tint-2: rgb(255 255 255 / 0.042); --nv-dark-elevation-tint-2: rgb(255 255 255 / 0.05);
--nv-dark-elevation-tint-3: rgb(255 255 255 / 0.06); --nv-dark-elevation-tint-3: rgb(255 255 255 / 0.07);
--nv-dark-elevation-tint-4: rgb(255 255 255 / 0.078); --nv-dark-elevation-tint-4: rgb(255 255 255 / 0.09);
--nv-dark-elevation-tint-5: rgb(255 255 255 / 0.095); --nv-dark-elevation-tint-5: rgb(255 255 255 / 0.11);
--nv-dark-material-frosted: color-mix(in oklab, rgb(36 36 40 / 0.62), var(--nv-brand) var(--nv-brand-tint)); --nv-dark-material-frosted: color-mix(in oklab, rgb(34 34 40 / 0.5), var(--nv-brand) var(--nv-brand-tint));
--nv-dark-material-glass: color-mix(in oklab, rgb(44 44 48 / 0.5), var(--nv-brand) var(--nv-brand-tint)); --nv-dark-material-glass: color-mix(in oklab, rgb(44 44 52 / 0.36), var(--nv-brand) var(--nv-brand-tint));
--nv-dark-material-border: rgb(255 255 255 / 0.1); --nv-dark-material-border: rgb(255 255 255 / 0.14);
/* --- Window controls --------------------------------------------------------- */ /* --- Window controls --------------------------------------------------------- */
--nv-dark-window-close: var(--nv-palette-window-close); --nv-dark-window-close: var(--nv-palette-window-close);
@ -1182,6 +1184,14 @@
margin: 0; margin: 0;
min-height: 100svh; min-height: 100svh;
background-color: var(--nv-color-background); background-color: var(--nv-color-background);
/* The canvas is lit, not painted: a wash of the accent falls in from the top
corner and a fainter one pools at the opposite foot. It is what gives
translucent surfaces something to be translucent against, and keeps a
page of solid panels from reading as one flat field. */
background-image:
radial-gradient(120% 80% at 0% 0%, color-mix(in oklab, var(--nv-color-accent) light-dark(10%, 16%), transparent), transparent 60%),
radial-gradient(90% 70% at 100% 100%, color-mix(in oklab, var(--nv-color-accent) light-dark(6%, 10%), transparent), transparent 60%);
background-attachment: fixed;
color: var(--nv-color-text-primary); color: var(--nv-color-text-primary);
font: var(--nv-font-body); font: var(--nv-font-body);
letter-spacing: var(--nv-letter-spacing-normal); letter-spacing: var(--nv-letter-spacing-normal);
@ -1841,6 +1851,12 @@
--_fg: var(--nv-color-on-accent); --_fg: var(--nv-color-on-accent);
--_border: transparent; --_border: transparent;
--_sheen: var(--nv-sheen-filled); --_sheen: var(--nv-sheen-filled);
/* A filled key gives off a little of its own color: the glow is what makes
it read as lit rather than printed. */
--_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-2),
0 6px 16px -8px color-mix(in oklab, var(--_bg) 80%, transparent);
--_shadow-hover: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-3),
0 8px 22px -8px color-mix(in oklab, var(--_bg) 85%, transparent);
font-weight: var(--nv-font-weight-semibold); font-weight: var(--nv-font-weight-semibold);
} }
@ -1851,6 +1867,10 @@
--_fg: var(--nv-color-on-danger); --_fg: var(--nv-color-on-danger);
--_border: transparent; --_border: transparent;
--_sheen: var(--nv-sheen-filled); --_sheen: var(--nv-sheen-filled);
--_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-2),
0 6px 16px -8px color-mix(in oklab, var(--_bg) 80%, transparent);
--_shadow-hover: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-3),
0 8px 22px -8px color-mix(in oklab, var(--_bg) 85%, transparent);
--nv-color-focus-ring: var(--nv-color-danger-border); --nv-color-focus-ring: var(--nv-color-danger-border);
font-weight: var(--nv-font-weight-semibold); font-weight: var(--nv-font-weight-semibold);
} }
@ -1867,6 +1887,14 @@
--_shadow-active: var(--nv-elevation-inset-sm); --_shadow-active: var(--nv-elevation-inset-sm);
} }
/* A ghost has no material to lose, so disabling it only dims the label —
it does not suddenly grow a well its enabled siblings never had. */
.nv-button--ghost:disabled,
.nv-button--ghost[aria-disabled="true"] {
background-color: transparent;
border-color: transparent;
}
@media (hover: hover) { @media (hover: hover) {
.nv-button--ghost:hover:not(:disabled, [aria-disabled="true"]) { .nv-button--ghost:hover:not(:disabled, [aria-disabled="true"]) {
color: var(--nv-color-text-primary); color: var(--nv-color-text-primary);
@ -2075,8 +2103,10 @@
min-inline-size: 0; min-inline-size: 0;
block-size: var(--_height); block-size: var(--_height);
padding-inline: var(--_padding); padding-inline: var(--_padding);
/* A well in dark, where recess reads as shade; paper in light, where a grey
background-color: var(--nv-color-surface-inset); well reads as a field that has been switched off. The inset shadow and
ledge carry the recess either way. */
background-color: light-dark(var(--nv-color-surface), var(--nv-color-surface-inset));
color: var(--nv-color-text-primary); color: var(--nv-color-text-primary);
border: var(--nv-border-width) solid var(--_border); border: var(--nv-border-width) solid var(--_border);
border-radius: var(--_radius); border-radius: var(--_radius);
@ -2150,7 +2180,13 @@
padding: 0; padding: 0;
} }
.nv-input--color::-webkit-color-swatch, .nv-input--color::-webkit-color-swatch {
border: var(--nv-border-width) solid var(--nv-color-border);
border-radius: calc(var(--nv-radius-md) - var(--nv-space-1));
}
/* Separate rules on purpose: a selector list that names another engine's
pseudo-element is invalid as a whole, and each browser would drop both. */
.nv-input--color::-moz-color-swatch { .nv-input--color::-moz-color-swatch {
border: var(--nv-border-width) solid var(--nv-color-border); border: var(--nv-border-width) solid var(--nv-color-border);
border-radius: calc(var(--nv-radius-md) - var(--nv-space-1)); border-radius: calc(var(--nv-radius-md) - var(--nv-space-1));
@ -2243,6 +2279,9 @@
.nv-radio { .nv-radio {
position: relative; position: relative;
flex: none; flex: none;
/* The marks are drawn in em; pinning the size keeps them the same whatever
the label around them is set in. */
font-size: var(--nv-font-size-md);
inline-size: var(--nv-space-5); inline-size: var(--nv-space-5);
block-size: var(--nv-space-5); block-size: var(--nv-space-5);
margin: 0; margin: 0;
@ -2407,7 +2446,10 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--nv-space-2-5); gap: var(--nv-space-2-5);
/* Labelled at control size, so a row of switches and checkboxes sits level
with the buttons and fields beside it. */
font: var(--nv-font-body); font: var(--nv-font-body);
font-size: var(--nv-font-size-sm);
cursor: pointer; cursor: pointer;
} }
@ -2439,7 +2481,11 @@
========================================================================== */ ========================================================================== */
.nv-card { .nv-card {
--_bg: var(--nv-color-surface); /* Content surfaces are mostly solid: enough of the canvas comes through to
tie a card to the light around it, never enough to compete with what it
holds. The blur keeps anything busy behind it (a bed, an image) from
reading through as texture. */
--_bg: color-mix(in oklab, var(--nv-color-surface) 90%, transparent);
--_border: var(--nv-color-border-subtle); --_border: var(--nv-color-border-subtle);
--_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-1); --_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-1);
--_sheen: var(--nv-sheen-surface); --_sheen: var(--nv-sheen-surface);
@ -2456,6 +2502,8 @@
border: var(--nv-border-width) solid var(--_border); border: var(--nv-border-width) solid var(--_border);
border-radius: var(--nv-radius-lg); border-radius: var(--nv-radius-lg);
box-shadow: var(--_shadow); box-shadow: var(--_shadow);
backdrop-filter: var(--nv-backdrop-glass);
-webkit-backdrop-filter: var(--nv-backdrop-glass);
/* Children are clipped to the corner radius so media and inset regions /* Children are clipped to the corner radius so media and inset regions
cannot square off the card. */ cannot square off the card. */
@ -2464,17 +2512,17 @@
} }
.nv-card--elevated { .nv-card--elevated {
--_bg: var(--nv-color-surface-elevated); --_bg: color-mix(in oklab, var(--nv-color-surface-elevated) 90%, transparent);
--_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-2); --_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-2);
} }
.nv-card--floating { .nv-card--floating {
--_bg: var(--nv-color-surface-elevated); --_bg: color-mix(in oklab, var(--nv-color-surface-elevated) 88%, transparent);
--_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-3); --_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-3);
} }
.nv-card--inset { .nv-card--inset {
--_bg: var(--nv-color-surface-inset); --_bg: color-mix(in oklab, var(--nv-color-surface-inset) 85%, transparent);
--_shadow: var(--nv-elevation-inset-md), var(--nv-ledge); --_shadow: var(--nv-elevation-inset-md), var(--nv-ledge);
--_sheen: none; --_sheen: none;
--_border: var(--nv-color-border-subtle); --_border: var(--nv-color-border-subtle);
@ -2625,8 +2673,13 @@
max-block-size: min(42rem, calc(100svh - var(--nv-space-12))); max-block-size: min(42rem, calc(100svh - var(--nv-space-12)));
padding: 0; padding: 0;
background-color: var(--nv-color-surface-elevated); /* The dialog sits over a dimmed, blurred page, so it can afford to let a
little of it through: it reads as a pane lifted off the page rather than
a card pasted over it. */
background-color: color-mix(in oklab, var(--nv-color-surface-elevated) 86%, transparent);
background-image: var(--nv-sheen-surface); background-image: var(--nv-sheen-surface);
backdrop-filter: var(--nv-backdrop-frosted);
-webkit-backdrop-filter: var(--nv-backdrop-frosted);
color: var(--nv-color-text-primary); color: var(--nv-color-text-primary);
border: var(--nv-border-width) solid var(--nv-color-border-subtle); border: var(--nv-border-width) solid var(--nv-color-border-subtle);
border-radius: var(--nv-radius-xl); border-radius: var(--nv-radius-xl);
@ -2815,11 +2868,12 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--nv-space-4); flex-wrap: wrap;
gap: var(--nv-space-2) var(--nv-space-4);
padding: var(--nv-space-2) var(--nv-space-4); padding: var(--nv-space-2) var(--nv-space-4);
min-block-size: var(--nv-control-height-lg); min-block-size: var(--nv-control-height-lg);
background-color: var(--nv-material-frosted-bg); background-color: var(--nv-material-frosted-bg);
background-image: var(--nv-sheen-raised);
border-block-end: var(--nv-border-width) solid var(--nv-color-border-subtle); border-block-end: var(--nv-border-width) solid var(--nv-color-border-subtle);
/* The travelling selection marker sits behind its item at z-index -1; the /* The travelling selection marker sits behind its item at z-index -1; the
@ -2841,6 +2895,7 @@
.nv-nav--plain { .nv-nav--plain {
background-color: var(--nv-color-surface); background-color: var(--nv-color-surface);
background-image: var(--nv-sheen-raised);
backdrop-filter: none; backdrop-filter: none;
-webkit-backdrop-filter: none; -webkit-backdrop-filter: none;
} }
@ -2859,6 +2914,7 @@
background-color: transparent; background-color: transparent;
border-block-end: 0; border-block-end: 0;
background-image: none;
box-shadow: none; box-shadow: none;
backdrop-filter: none; backdrop-filter: none;
-webkit-backdrop-filter: none; -webkit-backdrop-filter: none;
@ -2883,6 +2939,15 @@
padding: 0; padding: 0;
list-style: none; list-style: none;
min-inline-size: 0; min-inline-size: 0;
/* On a narrow screen a long list scrolls inside the bar instead of pushing
the page sideways. */
max-inline-size: 100%;
overflow-x: auto;
scrollbar-width: none;
}
.nv-nav__list::-webkit-scrollbar {
display: none;
} }
.nv-nav__spacer { .nv-nav__spacer {
@ -3030,11 +3095,15 @@
gap: var(--nv-space-1); gap: var(--nv-space-1);
inline-size: 15rem; inline-size: 15rem;
block-size: 100svh; block-size: 100svh;
flex-wrap: nowrap;
padding: var(--nv-space-4) var(--nv-space-3); padding: var(--nv-space-4) var(--nv-space-3);
/* A sidebar is a pane of the canvas rather than chrome over content, so it
background-color: var(--nv-color-background-subtle); stays mostly opaque — but it lets the light of the canvas through, which
backdrop-filter: none; is what stops it reading as a grey slab beside the page. */
-webkit-backdrop-filter: none; background-color: color-mix(in oklab, var(--nv-color-background-subtle) 72%, transparent);
background-image: var(--nv-sheen-surface);
backdrop-filter: var(--nv-backdrop-frosted);
-webkit-backdrop-filter: var(--nv-backdrop-frosted);
border-block-end: 0; border-block-end: 0;
border-inline-end: var(--nv-border-width) solid var(--nv-color-border-subtle); border-inline-end: var(--nv-border-width) solid var(--nv-color-border-subtle);
box-shadow: none; box-shadow: none;
@ -3076,10 +3145,10 @@
.nv-nav-tabs { .nv-nav-tabs {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
max-inline-size: 100%;
gap: var(--nv-space-0-5); gap: var(--nv-space-0-5);
padding: var(--nv-space-1); padding: var(--nv-space-1);
background-color: color-mix(in oklab, var(--nv-color-surface-inset) 80%, transparent);
background-color: var(--nv-color-surface-inset);
border: var(--nv-border-width) solid var(--nv-color-border-subtle); border: var(--nv-border-width) solid var(--nv-color-border-subtle);
border-radius: var(--nv-radius-md); border-radius: var(--nv-radius-md);
box-shadow: var(--nv-elevation-inset-md), var(--nv-ledge); box-shadow: var(--nv-elevation-inset-md), var(--nv-ledge);
@ -3198,6 +3267,7 @@
margin-block-start: var(--nv-space-2); margin-block-start: var(--nv-space-2);
background-color: var(--nv-material-frosted-bg); background-color: var(--nv-material-frosted-bg);
background-image: var(--nv-sheen-surface);
border: var(--nv-border-width) solid var(--nv-material-frosted-border); border: var(--nv-border-width) solid var(--nv-material-frosted-border);
border-radius: var(--nv-radius-lg); border-radius: var(--nv-radius-lg);
box-shadow: var(--nv-material-frosted-shadow); box-shadow: var(--nv-material-frosted-shadow);
@ -3940,6 +4010,7 @@
min-inline-size: 0; min-inline-size: 0;
background-color: var(--nv-color-surface); background-color: var(--nv-color-surface);
background-image: var(--nv-sheen-surface);
color: var(--nv-color-text-primary); color: var(--nv-color-text-primary);
border: var(--nv-border-width) solid var(--nv-color-border-subtle); border: var(--nv-border-width) solid var(--nv-color-border-subtle);
border-radius: var(--nv-radius-xl); border-radius: var(--nv-radius-xl);

View file

@ -24,6 +24,14 @@ body {
margin: 0; margin: 0;
min-height: 100svh; min-height: 100svh;
background-color: var(--nv-color-background); background-color: var(--nv-color-background);
/* The canvas is lit, not painted: a wash of the accent falls in from the top
corner and a fainter one pools at the opposite foot. It is what gives
translucent surfaces something to be translucent against, and keeps a
page of solid panels from reading as one flat field. */
background-image:
radial-gradient(120% 80% at 0% 0%, color-mix(in oklab, var(--nv-color-accent) light-dark(10%, 16%), transparent), transparent 60%),
radial-gradient(90% 70% at 100% 100%, color-mix(in oklab, var(--nv-color-accent) light-dark(6%, 10%), transparent), transparent 60%);
background-attachment: fixed;
color: var(--nv-color-text-primary); color: var(--nv-color-text-primary);
font: var(--nv-font-body); font: var(--nv-font-body);
letter-spacing: var(--nv-letter-spacing-normal); letter-spacing: var(--nv-letter-spacing-normal);

View file

@ -123,6 +123,12 @@
--_fg: var(--nv-color-on-accent); --_fg: var(--nv-color-on-accent);
--_border: transparent; --_border: transparent;
--_sheen: var(--nv-sheen-filled); --_sheen: var(--nv-sheen-filled);
/* A filled key gives off a little of its own color: the glow is what makes
it read as lit rather than printed. */
--_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-2),
0 6px 16px -8px color-mix(in oklab, var(--_bg) 80%, transparent);
--_shadow-hover: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-3),
0 8px 22px -8px color-mix(in oklab, var(--_bg) 85%, transparent);
font-weight: var(--nv-font-weight-semibold); font-weight: var(--nv-font-weight-semibold);
} }
@ -133,6 +139,10 @@
--_fg: var(--nv-color-on-danger); --_fg: var(--nv-color-on-danger);
--_border: transparent; --_border: transparent;
--_sheen: var(--nv-sheen-filled); --_sheen: var(--nv-sheen-filled);
--_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-2),
0 6px 16px -8px color-mix(in oklab, var(--_bg) 80%, transparent);
--_shadow-hover: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-3),
0 8px 22px -8px color-mix(in oklab, var(--_bg) 85%, transparent);
--nv-color-focus-ring: var(--nv-color-danger-border); --nv-color-focus-ring: var(--nv-color-danger-border);
font-weight: var(--nv-font-weight-semibold); font-weight: var(--nv-font-weight-semibold);
} }
@ -149,6 +159,14 @@
--_shadow-active: var(--nv-elevation-inset-sm); --_shadow-active: var(--nv-elevation-inset-sm);
} }
/* A ghost has no material to lose, so disabling it only dims the label —
it does not suddenly grow a well its enabled siblings never had. */
.nv-button--ghost:disabled,
.nv-button--ghost[aria-disabled="true"] {
background-color: transparent;
border-color: transparent;
}
@media (hover: hover) { @media (hover: hover) {
.nv-button--ghost:hover:not(:disabled, [aria-disabled="true"]) { .nv-button--ghost:hover:not(:disabled, [aria-disabled="true"]) {
color: var(--nv-color-text-primary); color: var(--nv-color-text-primary);

View file

@ -14,7 +14,11 @@
========================================================================== */ ========================================================================== */
.nv-card { .nv-card {
--_bg: var(--nv-color-surface); /* Content surfaces are mostly solid: enough of the canvas comes through to
tie a card to the light around it, never enough to compete with what it
holds. The blur keeps anything busy behind it (a bed, an image) from
reading through as texture. */
--_bg: color-mix(in oklab, var(--nv-color-surface) 90%, transparent);
--_border: var(--nv-color-border-subtle); --_border: var(--nv-color-border-subtle);
--_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-1); --_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-1);
--_sheen: var(--nv-sheen-surface); --_sheen: var(--nv-sheen-surface);
@ -31,6 +35,8 @@
border: var(--nv-border-width) solid var(--_border); border: var(--nv-border-width) solid var(--_border);
border-radius: var(--nv-radius-lg); border-radius: var(--nv-radius-lg);
box-shadow: var(--_shadow); box-shadow: var(--_shadow);
backdrop-filter: var(--nv-backdrop-glass);
-webkit-backdrop-filter: var(--nv-backdrop-glass);
/* Children are clipped to the corner radius so media and inset regions /* Children are clipped to the corner radius so media and inset regions
cannot square off the card. */ cannot square off the card. */
@ -39,17 +45,17 @@
} }
.nv-card--elevated { .nv-card--elevated {
--_bg: var(--nv-color-surface-elevated); --_bg: color-mix(in oklab, var(--nv-color-surface-elevated) 90%, transparent);
--_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-2); --_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-2);
} }
.nv-card--floating { .nv-card--floating {
--_bg: var(--nv-color-surface-elevated); --_bg: color-mix(in oklab, var(--nv-color-surface-elevated) 88%, transparent);
--_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-3); --_shadow: var(--nv-bevel), var(--nv-outline), var(--nv-elevation-3);
} }
.nv-card--inset { .nv-card--inset {
--_bg: var(--nv-color-surface-inset); --_bg: color-mix(in oklab, var(--nv-color-surface-inset) 85%, transparent);
--_shadow: var(--nv-elevation-inset-md), var(--nv-ledge); --_shadow: var(--nv-elevation-inset-md), var(--nv-ledge);
--_sheen: none; --_sheen: none;
--_border: var(--nv-color-border-subtle); --_border: var(--nv-color-border-subtle);

View file

@ -23,8 +23,13 @@
max-block-size: min(42rem, calc(100svh - var(--nv-space-12))); max-block-size: min(42rem, calc(100svh - var(--nv-space-12)));
padding: 0; padding: 0;
background-color: var(--nv-color-surface-elevated); /* The dialog sits over a dimmed, blurred page, so it can afford to let a
little of it through: it reads as a pane lifted off the page rather than
a card pasted over it. */
background-color: color-mix(in oklab, var(--nv-color-surface-elevated) 86%, transparent);
background-image: var(--nv-sheen-surface); background-image: var(--nv-sheen-surface);
backdrop-filter: var(--nv-backdrop-frosted);
-webkit-backdrop-filter: var(--nv-backdrop-frosted);
color: var(--nv-color-text-primary); color: var(--nv-color-text-primary);
border: var(--nv-border-width) solid var(--nv-color-border-subtle); border: var(--nv-border-width) solid var(--nv-color-border-subtle);
border-radius: var(--nv-radius-xl); border-radius: var(--nv-radius-xl);

View file

@ -59,8 +59,10 @@
min-inline-size: 0; min-inline-size: 0;
block-size: var(--_height); block-size: var(--_height);
padding-inline: var(--_padding); padding-inline: var(--_padding);
/* A well in dark, where recess reads as shade; paper in light, where a grey
background-color: var(--nv-color-surface-inset); well reads as a field that has been switched off. The inset shadow and
ledge carry the recess either way. */
background-color: light-dark(var(--nv-color-surface), var(--nv-color-surface-inset));
color: var(--nv-color-text-primary); color: var(--nv-color-text-primary);
border: var(--nv-border-width) solid var(--_border); border: var(--nv-border-width) solid var(--_border);
border-radius: var(--_radius); border-radius: var(--_radius);
@ -134,7 +136,13 @@ textarea.nv-input {
padding: 0; padding: 0;
} }
.nv-input--color::-webkit-color-swatch, .nv-input--color::-webkit-color-swatch {
border: var(--nv-border-width) solid var(--nv-color-border);
border-radius: calc(var(--nv-radius-md) - var(--nv-space-1));
}
/* Separate rules on purpose: a selector list that names another engine's
pseudo-element is invalid as a whole, and each browser would drop both. */
.nv-input--color::-moz-color-swatch { .nv-input--color::-moz-color-swatch {
border: var(--nv-border-width) solid var(--nv-color-border); border: var(--nv-border-width) solid var(--nv-color-border);
border-radius: calc(var(--nv-radius-md) - var(--nv-space-1)); border-radius: calc(var(--nv-radius-md) - var(--nv-space-1));
@ -227,6 +235,9 @@ textarea.nv-input {
.nv-radio { .nv-radio {
position: relative; position: relative;
flex: none; flex: none;
/* The marks are drawn in em; pinning the size keeps them the same whatever
the label around them is set in. */
font-size: var(--nv-font-size-md);
inline-size: var(--nv-space-5); inline-size: var(--nv-space-5);
block-size: var(--nv-space-5); block-size: var(--nv-space-5);
margin: 0; margin: 0;
@ -391,7 +402,10 @@ textarea.nv-input {
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--nv-space-2-5); gap: var(--nv-space-2-5);
/* Labelled at control size, so a row of switches and checkboxes sits level
with the buttons and fields beside it. */
font: var(--nv-font-body); font: var(--nv-font-body);
font-size: var(--nv-font-size-sm);
cursor: pointer; cursor: pointer;
} }

View file

@ -43,6 +43,7 @@
margin-block-start: var(--nv-space-2); margin-block-start: var(--nv-space-2);
background-color: var(--nv-material-frosted-bg); background-color: var(--nv-material-frosted-bg);
background-image: var(--nv-sheen-surface);
border: var(--nv-border-width) solid var(--nv-material-frosted-border); border: var(--nv-border-width) solid var(--nv-material-frosted-border);
border-radius: var(--nv-radius-lg); border-radius: var(--nv-radius-lg);
box-shadow: var(--nv-material-frosted-shadow); box-shadow: var(--nv-material-frosted-shadow);

View file

@ -20,11 +20,12 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: var(--nv-space-4); flex-wrap: wrap;
gap: var(--nv-space-2) var(--nv-space-4);
padding: var(--nv-space-2) var(--nv-space-4); padding: var(--nv-space-2) var(--nv-space-4);
min-block-size: var(--nv-control-height-lg); min-block-size: var(--nv-control-height-lg);
background-color: var(--nv-material-frosted-bg); background-color: var(--nv-material-frosted-bg);
background-image: var(--nv-sheen-raised);
border-block-end: var(--nv-border-width) solid var(--nv-color-border-subtle); border-block-end: var(--nv-border-width) solid var(--nv-color-border-subtle);
/* The travelling selection marker sits behind its item at z-index -1; the /* The travelling selection marker sits behind its item at z-index -1; the
@ -46,6 +47,7 @@
.nv-nav--plain { .nv-nav--plain {
background-color: var(--nv-color-surface); background-color: var(--nv-color-surface);
background-image: var(--nv-sheen-raised);
backdrop-filter: none; backdrop-filter: none;
-webkit-backdrop-filter: none; -webkit-backdrop-filter: none;
} }
@ -64,6 +66,7 @@
background-color: transparent; background-color: transparent;
border-block-end: 0; border-block-end: 0;
background-image: none;
box-shadow: none; box-shadow: none;
backdrop-filter: none; backdrop-filter: none;
-webkit-backdrop-filter: none; -webkit-backdrop-filter: none;
@ -88,6 +91,15 @@
padding: 0; padding: 0;
list-style: none; list-style: none;
min-inline-size: 0; min-inline-size: 0;
/* On a narrow screen a long list scrolls inside the bar instead of pushing
the page sideways. */
max-inline-size: 100%;
overflow-x: auto;
scrollbar-width: none;
}
.nv-nav__list::-webkit-scrollbar {
display: none;
} }
.nv-nav__spacer { .nv-nav__spacer {
@ -235,11 +247,15 @@
gap: var(--nv-space-1); gap: var(--nv-space-1);
inline-size: 15rem; inline-size: 15rem;
block-size: 100svh; block-size: 100svh;
flex-wrap: nowrap;
padding: var(--nv-space-4) var(--nv-space-3); padding: var(--nv-space-4) var(--nv-space-3);
/* A sidebar is a pane of the canvas rather than chrome over content, so it
background-color: var(--nv-color-background-subtle); stays mostly opaque — but it lets the light of the canvas through, which
backdrop-filter: none; is what stops it reading as a grey slab beside the page. */
-webkit-backdrop-filter: none; background-color: color-mix(in oklab, var(--nv-color-background-subtle) 72%, transparent);
background-image: var(--nv-sheen-surface);
backdrop-filter: var(--nv-backdrop-frosted);
-webkit-backdrop-filter: var(--nv-backdrop-frosted);
border-block-end: 0; border-block-end: 0;
border-inline-end: var(--nv-border-width) solid var(--nv-color-border-subtle); border-inline-end: var(--nv-border-width) solid var(--nv-color-border-subtle);
box-shadow: none; box-shadow: none;
@ -281,10 +297,10 @@
.nv-nav-tabs { .nv-nav-tabs {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
max-inline-size: 100%;
gap: var(--nv-space-0-5); gap: var(--nv-space-0-5);
padding: var(--nv-space-1); padding: var(--nv-space-1);
background-color: color-mix(in oklab, var(--nv-color-surface-inset) 80%, transparent);
background-color: var(--nv-color-surface-inset);
border: var(--nv-border-width) solid var(--nv-color-border-subtle); border: var(--nv-border-width) solid var(--nv-color-border-subtle);
border-radius: var(--nv-radius-md); border-radius: var(--nv-radius-md);
box-shadow: var(--nv-elevation-inset-md), var(--nv-ledge); box-shadow: var(--nv-elevation-inset-md), var(--nv-ledge);

View file

@ -37,6 +37,7 @@
min-inline-size: 0; min-inline-size: 0;
background-color: var(--nv-color-surface); background-color: var(--nv-color-surface);
background-image: var(--nv-sheen-surface);
color: var(--nv-color-text-primary); color: var(--nv-color-text-primary);
border: var(--nv-border-width) solid var(--nv-color-border-subtle); border: var(--nv-border-width) solid var(--nv-color-border-subtle);
border-radius: var(--nv-radius-xl); border-radius: var(--nv-radius-xl);

View file

@ -21,7 +21,7 @@
:root, :root,
[data-nv-brand] { [data-nv-brand] {
/* --- Canvas and surfaces ----------------------------------------------- */ /* --- Canvas and surfaces ----------------------------------------------- */
--nv-dark-background: color-mix(in oklab, #121214, var(--nv-brand) var(--nv-brand-tint)); --nv-dark-background: color-mix(in oklab, #0f0f12, var(--nv-brand) var(--nv-brand-tint));
--nv-dark-background-subtle: color-mix(in oklab, #18181b, var(--nv-brand) var(--nv-brand-tint)); --nv-dark-background-subtle: color-mix(in oklab, #18181b, var(--nv-brand) var(--nv-brand-tint));
--nv-dark-surface: color-mix(in oklab, #1f1f22, var(--nv-brand) var(--nv-brand-tint)); --nv-dark-surface: color-mix(in oklab, #1f1f22, var(--nv-brand) var(--nv-brand-tint));
--nv-dark-surface-elevated: color-mix(in oklab, #2a2a2e, var(--nv-brand) var(--nv-brand-tint)); --nv-dark-surface-elevated: color-mix(in oklab, #2a2a2e, var(--nv-brand) var(--nv-brand-tint));
@ -115,33 +115,33 @@
--nv-dark-shadow-penumbra: rgb(0 0 0 / 0.5); --nv-dark-shadow-penumbra: rgb(0 0 0 / 0.5);
--nv-dark-shadow-umbra: rgb(0 0 0 / 0.55); --nv-dark-shadow-umbra: rgb(0 0 0 / 0.55);
--nv-dark-shadow-inset: rgb(0 0 0 / 0.65); --nv-dark-shadow-inset: rgb(0 0 0 / 0.65);
--nv-dark-highlight: rgb(255 255 255 / 0.11); --nv-dark-highlight: rgb(255 255 255 / 0.15);
--nv-dark-highlight-strong: rgb(255 255 255 / 0.17); --nv-dark-highlight-strong: rgb(255 255 255 / 0.24);
/* The contact line is what separates graphite from graphite: a raised /* The contact line is what separates graphite from graphite: a raised
surface over a dark canvas has no shadow to show, but it always has an surface over a dark canvas has no shadow to show, but it always has an
edge. */ edge. */
--nv-dark-lowlight: rgb(0 0 0 / 0.42); --nv-dark-lowlight: rgb(0 0 0 / 0.5);
--nv-dark-outline: rgb(0 0 0 / 0.72); --nv-dark-outline: rgb(0 0 0 / 0.72);
--nv-dark-sheen-top: rgb(255 255 255 / 0.06); --nv-dark-sheen-top: rgb(255 255 255 / 0.09);
--nv-dark-sheen-bottom: rgb(0 0 0 / 0.09); --nv-dark-sheen-bottom: rgb(0 0 0 / 0.18);
--nv-dark-sheen-strong-top: rgb(255 255 255 / 0.2); --nv-dark-sheen-strong-top: rgb(255 255 255 / 0.3);
--nv-dark-sheen-strong-bottom: rgb(0 0 0 / 0.12); --nv-dark-sheen-strong-bottom: rgb(0 0 0 / 0.2);
--nv-dark-knob: #f4f3ef; --nv-dark-knob: #f4f3ef;
--nv-dark-knob-shade: rgb(40 32 20 / 0.24); --nv-dark-knob-shade: rgb(40 32 20 / 0.3);
/* The higher a surface sits, the more light reaches it. */ /* The higher a surface sits, the more light reaches it. */
--nv-dark-elevation-tint-1: rgb(255 255 255 / 0.025); --nv-dark-elevation-tint-1: rgb(255 255 255 / 0.03);
--nv-dark-elevation-tint-2: rgb(255 255 255 / 0.042); --nv-dark-elevation-tint-2: rgb(255 255 255 / 0.05);
--nv-dark-elevation-tint-3: rgb(255 255 255 / 0.06); --nv-dark-elevation-tint-3: rgb(255 255 255 / 0.07);
--nv-dark-elevation-tint-4: rgb(255 255 255 / 0.078); --nv-dark-elevation-tint-4: rgb(255 255 255 / 0.09);
--nv-dark-elevation-tint-5: rgb(255 255 255 / 0.095); --nv-dark-elevation-tint-5: rgb(255 255 255 / 0.11);
--nv-dark-material-frosted: color-mix(in oklab, rgb(36 36 40 / 0.62), var(--nv-brand) var(--nv-brand-tint)); --nv-dark-material-frosted: color-mix(in oklab, rgb(34 34 40 / 0.5), var(--nv-brand) var(--nv-brand-tint));
--nv-dark-material-glass: color-mix(in oklab, rgb(44 44 48 / 0.5), var(--nv-brand) var(--nv-brand-tint)); --nv-dark-material-glass: color-mix(in oklab, rgb(44 44 52 / 0.36), var(--nv-brand) var(--nv-brand-tint));
--nv-dark-material-border: rgb(255 255 255 / 0.1); --nv-dark-material-border: rgb(255 255 255 / 0.14);
/* --- Window controls --------------------------------------------------------- */ /* --- Window controls --------------------------------------------------------- */
--nv-dark-window-close: var(--nv-palette-window-close); --nv-dark-window-close: var(--nv-palette-window-close);

View file

@ -39,7 +39,7 @@
--nv-light-background-subtle: color-mix(in oklab, #eeece6, 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: #fbfbfa;
--nv-light-surface-elevated: #f8f8f6; --nv-light-surface-elevated: #f8f8f6;
--nv-light-surface-inset: color-mix(in oklab, #e3e2dd, var(--nv-brand) var(--nv-brand-tint)); --nv-light-surface-inset: color-mix(in oklab, #eeede8, 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-hover: color-mix(in oklab, #f1f0ec, var(--nv-brand) var(--nv-brand-tint));
--nv-light-surface-active: color-mix(in oklab, #e6e5e0, var(--nv-brand) var(--nv-brand-tint)); --nv-light-surface-active: color-mix(in oklab, #e6e5e0, var(--nv-brand) var(--nv-brand-tint));
--nv-light-scrim: rgb(28 24 18 / 0.34); --nv-light-scrim: rgb(28 24 18 / 0.34);
@ -135,22 +135,22 @@
/* --- Depth and material ------------------------------------------------- /* --- Depth and material -------------------------------------------------
Three shadow colors build every elevation level: an ambient contact Three shadow colors build every elevation level: an ambient contact
shadow, a soft penumbra, and a deeper umbra for high elevations. */ shadow, a soft penumbra, and a deeper umbra for high elevations. */
--nv-light-shadow-ambient: rgb(40 32 20 / 0.09); --nv-light-shadow-ambient: rgb(40 32 20 / 0.08);
--nv-light-shadow-penumbra: rgb(40 32 20 / 0.12); --nv-light-shadow-penumbra: rgb(40 32 20 / 0.1);
--nv-light-shadow-umbra: rgb(40 32 20 / 0.11); --nv-light-shadow-umbra: rgb(40 32 20 / 0.16);
--nv-light-shadow-inset: rgb(40 32 20 / 0.17); --nv-light-shadow-inset: rgb(40 32 20 / 0.14);
--nv-light-highlight: rgb(255 255 255 / 0.9); --nv-light-highlight: rgb(255 255 255 / 0.9);
--nv-light-highlight-strong: rgb(255 255 255 / 1); --nv-light-highlight-strong: rgb(255 255 255 / 1);
/* Paper already has a border doing the contact work, so the outline only /* Paper already has a border doing the contact work, so the outline only
softens it; the bottom shade is faint for the same reason. */ softens it; the bottom shade is faint for the same reason. */
--nv-light-lowlight: rgb(40 32 20 / 0.07); --nv-light-lowlight: rgb(40 32 20 / 0.09);
--nv-light-outline: rgb(40 32 20 / 0.05); --nv-light-outline: rgb(40 32 20 / 0.05);
--nv-light-sheen-top: rgb(255 255 255 / 0.75); --nv-light-sheen-top: rgb(255 255 255 / 0.9);
--nv-light-sheen-bottom: rgb(40 32 20 / 0.04); --nv-light-sheen-bottom: rgb(40 32 20 / 0.07);
--nv-light-sheen-strong-top: rgb(255 255 255 / 0.24); --nv-light-sheen-strong-top: rgb(255 255 255 / 0.32);
--nv-light-sheen-strong-bottom: rgb(20 16 10 / 0.1); --nv-light-sheen-strong-bottom: rgb(20 16 10 / 0.16);
--nv-light-knob: var(--nv-palette-neutral-0); --nv-light-knob: var(--nv-palette-neutral-0);
--nv-light-knob-shade: rgb(40 32 20 / 0.13); --nv-light-knob-shade: rgb(40 32 20 / 0.13);
@ -163,9 +163,9 @@
--nv-light-elevation-tint-4: transparent; --nv-light-elevation-tint-4: transparent;
--nv-light-elevation-tint-5: transparent; --nv-light-elevation-tint-5: transparent;
--nv-light-material-frosted: rgb(251 251 249 / 0.66); --nv-light-material-frosted: rgb(252 252 250 / 0.56);
--nv-light-material-glass: rgb(251 251 249 / 0.5); --nv-light-material-glass: rgb(252 252 250 / 0.4);
--nv-light-material-border: rgb(255 255 255 / 0.6); --nv-light-material-border: rgb(255 255 255 / 0.72);
/* --- Window controls --------------------------------------------------------- */ /* --- Window controls --------------------------------------------------------- */
--nv-light-window-close: var(--nv-palette-window-close); --nv-light-window-close: var(--nv-palette-window-close);

View file

@ -22,34 +22,35 @@
--nv-elevation-1: --nv-elevation-1:
0 1px 1px var(--nv-color-shadow-ambient), 0 1px 1px var(--nv-color-shadow-ambient),
0 1px 3px -1px var(--nv-color-shadow-penumbra); 0 2px 4px -1px var(--nv-color-shadow-penumbra),
0 6px 14px -8px var(--nv-color-shadow-umbra);
--nv-elevation-2: --nv-elevation-2:
0 1px 1px var(--nv-color-shadow-ambient), 0 1px 1px var(--nv-color-shadow-ambient),
0 2px 4px -1px var(--nv-color-shadow-penumbra), 0 3px 6px -2px var(--nv-color-shadow-penumbra),
0 4px 8px -4px var(--nv-color-shadow-umbra); 0 10px 20px -10px var(--nv-color-shadow-umbra);
--nv-elevation-3: --nv-elevation-3:
0 1px 1px var(--nv-color-shadow-ambient), 0 1px 2px var(--nv-color-shadow-ambient),
0 4px 8px -2px var(--nv-color-shadow-penumbra), 0 6px 12px -4px var(--nv-color-shadow-penumbra),
0 10px 20px -6px var(--nv-color-shadow-umbra); 0 18px 36px -12px var(--nv-color-shadow-umbra);
--nv-elevation-4: --nv-elevation-4:
0 1px 2px var(--nv-color-shadow-ambient), 0 1px 2px var(--nv-color-shadow-ambient),
0 8px 16px -4px var(--nv-color-shadow-penumbra), 0 10px 20px -6px var(--nv-color-shadow-penumbra),
0 20px 40px -10px var(--nv-color-shadow-umbra); 0 30px 60px -16px var(--nv-color-shadow-umbra);
--nv-elevation-5: --nv-elevation-5:
0 1px 2px var(--nv-color-shadow-ambient), 0 2px 3px var(--nv-color-shadow-ambient),
0 14px 28px -6px var(--nv-color-shadow-penumbra), 0 16px 32px -8px var(--nv-color-shadow-penumbra),
0 32px 64px -14px var(--nv-color-shadow-umbra); 0 44px 88px -20px var(--nv-color-shadow-umbra);
/* --- Inset --------------------------------------------------------------- /* --- Inset ---------------------------------------------------------------
Recessed surfaces: fields, wells, tracks, pressed controls. */ Recessed surfaces: fields, wells, tracks, pressed controls. */
--nv-elevation-inset-sm: inset 0 1px 2px var(--nv-color-shadow-inset); --nv-elevation-inset-sm: inset 0 1px 2px var(--nv-color-shadow-inset);
--nv-elevation-inset-md: --nv-elevation-inset-md:
inset 0 1px 1px var(--nv-color-shadow-inset), inset 0 1px 1px var(--nv-color-shadow-inset),
inset 0 2px 5px -1px var(--nv-color-shadow-inset); inset 0 3px 6px -2px var(--nv-color-shadow-inset);
--nv-elevation-inset-lg: --nv-elevation-inset-lg:
inset 0 2px 3px var(--nv-color-shadow-inset), inset 0 2px 3px var(--nv-color-shadow-inset),
inset 0 6px 12px -3px var(--nv-color-shadow-inset); inset 0 6px 12px -3px var(--nv-color-shadow-inset);

View file

@ -27,30 +27,31 @@
:root { :root {
/* --- Blur ---------------------------------------------------------------- */ /* --- Blur ---------------------------------------------------------------- */
--nv-blur-sm: 8px; --nv-blur-sm: 12px;
--nv-blur-md: 16px; --nv-blur-md: 24px;
--nv-blur-lg: 28px; --nv-blur-lg: 36px;
--nv-blur-xl: 44px; --nv-blur-xl: 56px;
/* Backdrops lose saturation when blurred; a touch of saturate() puts the /* Backdrops lose saturation when blurred; a touch of saturate() puts the
color back so frosted surfaces do not read as gray films. Moderate on color back so frosted surfaces do not read as gray films. Moderate on
purpose: the blur says "this floats", it is not the look itself. */ purpose: the blur says "this floats", it is not the look itself. */
--nv-backdrop-saturate: 160%; --nv-backdrop-saturate: 180%;
--nv-backdrop-frosted: blur(var(--nv-blur-md)) saturate(var(--nv-backdrop-saturate)); --nv-backdrop-frosted: blur(var(--nv-blur-md)) saturate(var(--nv-backdrop-saturate));
--nv-backdrop-glass: blur(var(--nv-blur-sm)) saturate(var(--nv-backdrop-saturate)); --nv-backdrop-glass: blur(var(--nv-blur-sm)) saturate(var(--nv-backdrop-saturate));
/* --- Sheen ------------------------------------------------------------------ /* --- Sheen ------------------------------------------------------------------
raised neutral controls: buttons, the selected tab, a titlebar raised neutral controls: buttons, the selected tab, a titlebar
filled saturated fills: primary and danger buttons, checked marks filled saturated fills: primary and danger buttons, checked marks
surface large surfaces: windows, dialogs, cards. The light fades out surface large surfaces: windows, dialogs, cards. Brightest along the
within the first stretch, so it reads as a lit top edge top edge, easing through the middle and settling into a faint
rather than as a gradient over the content. shade at the foot, so a panel reads as a curved, lit body
rather than as a flat sheet.
knob a round thumb: lit from above, shaded towards its rim */ knob a round thumb: lit from above, shaded towards its rim */
--nv-sheen-raised: linear-gradient(var(--nv-color-sheen-top), var(--nv-color-sheen-bottom)); --nv-sheen-raised: linear-gradient(var(--nv-color-sheen-top), var(--nv-color-sheen-bottom));
--nv-sheen-filled: linear-gradient(var(--nv-color-sheen-strong-top), var(--nv-color-sheen-strong-bottom)); --nv-sheen-filled: linear-gradient(var(--nv-color-sheen-strong-top), var(--nv-color-sheen-strong-bottom));
--nv-sheen-surface: linear-gradient(var(--nv-color-sheen-top), transparent 6rem); --nv-sheen-surface: linear-gradient(var(--nv-color-sheen-top), transparent 7rem, transparent 55%, var(--nv-color-sheen-bottom));
--nv-sheen-knob: radial-gradient(circle at 50% 30%, transparent 35%, var(--nv-color-knob-shade)); --nv-sheen-knob: radial-gradient(circle at 50% 22%, var(--nv-color-highlight-strong), transparent 45%), radial-gradient(circle at 50% 30%, transparent 40%, var(--nv-color-knob-shade));
--nv-backdrop-scrim: blur(var(--nv-blur-sm)) saturate(120%); --nv-backdrop-scrim: blur(var(--nv-blur-sm)) saturate(140%);
/* --- Material recipes ----------------------------------------------------- /* --- Material recipes -----------------------------------------------------
Each recipe is the full set of properties that defines the material. Each recipe is the full set of properties that defines the material.