mirror of
https://github.com/Nexoniarz/Niveus.git
synced 2026-11-02 20:24:26 +00:00
Found by driving Firefox 158 with real pointer, wheel and key input. - Time picker wheels used padding to reach the last rows. Firefox leaves bottom padding out of the scrollable area, so the last rows were unreachable and the 24H/AM/PM wheel could not scroll at all. Spacer pseudo-elements replace the padding. - Wheels can now be dragged with a mouse or pen, with inertia, a rubber-band at the ends and a spring back. Touch is left to the platform. - Theme changes no longer use a page-wide view transition. The snapshot could not blur what sits behind frosted glass, so every frosted surface went clear for the length of the cross-fade. - Dark shadows were invisible: black on a near-black canvas, with a deep negative spread tucking the blur under the element. The dark canvas is lifted, the shadows are stronger and the spreads milder. - Same-page links now travel (scroll-behavior: smooth, motion permitting). - data-nv-tristate: a checkbox that cycles unchecked, checked, partial; the browser can display a partial state but a click can never choose it. - Button groups show their pressed segment. GUIDELINES.md gains the cross-engine rules these defects taught, and makes Firefox the first browser to verify in. check.py, build.py and build.py --check pass. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
130 lines
6.1 KiB
CSS
130 lines
6.1 KiB
CSS
/* ==========================================================================
|
|
Niveus — Elevation
|
|
--------------------------------------------------------------------------
|
|
Depth is a scale, not a free choice. Each level describes one relationship
|
|
between a surface and what sits behind it:
|
|
|
|
0 flush painted on the canvas, no separation
|
|
1 resting cards, list rows, static panels
|
|
2 raised buttons, controls, anything that reacts to a pointer
|
|
3 floating popovers, menus, dropdowns, tooltips
|
|
4 lifted dialogs, sheets, detached panels
|
|
5 overlay the topmost layer, used sparingly
|
|
|
|
Every level is built from the same three shadow colors so depth stays
|
|
consistent between appearances: an ambient contact shadow that keeps the
|
|
edge crisp, a soft penumbra for the spread, and an umbra that only appears
|
|
once a surface is genuinely far from the canvas.
|
|
|
|
Two things keep a shadow visible, and both have failed before. The soft
|
|
layers use only a mild negative spread: a deep one tucks the blur under the
|
|
element and leaves almost nothing outside it. And the canvas has to be
|
|
lighter than the shadow colour — black cannot darken black — which is why the
|
|
dark canvas is not the darkest value it could be.
|
|
========================================================================== */
|
|
|
|
:root {
|
|
--nv-elevation-0: none;
|
|
|
|
--nv-elevation-1:
|
|
0 1px 1px var(--nv-color-shadow-ambient),
|
|
0 2px 4px -1px var(--nv-color-shadow-penumbra),
|
|
0 6px 14px -5px var(--nv-color-shadow-umbra);
|
|
|
|
--nv-elevation-2:
|
|
0 1px 1px var(--nv-color-shadow-ambient),
|
|
0 3px 6px -2px var(--nv-color-shadow-penumbra),
|
|
0 10px 20px -7px var(--nv-color-shadow-umbra);
|
|
|
|
--nv-elevation-3:
|
|
0 1px 2px var(--nv-color-shadow-ambient),
|
|
0 6px 12px -4px var(--nv-color-shadow-penumbra),
|
|
0 18px 36px -9px var(--nv-color-shadow-umbra);
|
|
|
|
--nv-elevation-4:
|
|
0 1px 2px var(--nv-color-shadow-ambient),
|
|
0 10px 20px -6px var(--nv-color-shadow-penumbra),
|
|
0 30px 60px -12px var(--nv-color-shadow-umbra);
|
|
|
|
--nv-elevation-5:
|
|
0 2px 3px var(--nv-color-shadow-ambient),
|
|
0 16px 32px -8px var(--nv-color-shadow-penumbra),
|
|
0 44px 88px -16px var(--nv-color-shadow-umbra);
|
|
|
|
/* --- Inset ---------------------------------------------------------------
|
|
Recessed surfaces: fields, wells, tracks, pressed controls. */
|
|
--nv-elevation-inset-sm: inset 0 1px 2px var(--nv-color-shadow-inset);
|
|
--nv-elevation-inset-md:
|
|
inset 0 1px 1px var(--nv-color-shadow-inset),
|
|
inset 0 3px 6px -2px var(--nv-color-shadow-inset);
|
|
--nv-elevation-inset-lg:
|
|
inset 0 2px 3px var(--nv-color-shadow-inset),
|
|
inset 0 6px 12px -3px var(--nv-color-shadow-inset);
|
|
|
|
/* --- Highlight -----------------------------------------------------------
|
|
The thin catch of light along the top edge of a raised surface. This is
|
|
what makes Niveus read as material rather than as a rectangle with a
|
|
shadow. Always paired with an elevation, never used alone. */
|
|
--nv-highlight-top: inset 0 1px 0 var(--nv-color-highlight);
|
|
--nv-highlight-top-strong: inset 0 1px 0 var(--nv-color-highlight-strong);
|
|
--nv-highlight-edge:
|
|
inset 0 1px 0 var(--nv-color-highlight),
|
|
inset 0 0 0 1px var(--nv-color-border-subtle);
|
|
|
|
/* --- Bevel -----------------------------------------------------------------
|
|
The highlight's other half. A raised face is lit along its top edge and
|
|
shaded along its bottom one; together they are the bevel, and the bevel is
|
|
what makes a Niveus control look like something a finger could press.
|
|
Raised controls and surfaces take the full bevel; the highlight alone is
|
|
for things that sit flush. */
|
|
--nv-lowlight-bottom: inset 0 -1px 0 var(--nv-color-lowlight);
|
|
--nv-bevel:
|
|
inset 0 1px 0 var(--nv-color-highlight),
|
|
inset 0 -1px 0 var(--nv-color-lowlight);
|
|
|
|
/* --- Outline ---------------------------------------------------------------
|
|
The contact line: a hairline just outside a raised surface, where it meets
|
|
whatever it rests on. In dark it is near-black and does most of the
|
|
separating; in light it only softens the border beside it. */
|
|
--nv-outline: 0 0 0 1px var(--nv-color-outline);
|
|
|
|
/* --- Ledge -----------------------------------------------------------------
|
|
A recess catches light on its *lower* lip, the edge facing the viewer.
|
|
Paired with an inset shadow, it turns a field from a dark rectangle into
|
|
a well cut into the surface. */
|
|
--nv-ledge: 0 1px 0 var(--nv-color-highlight);
|
|
|
|
/* --- Focus ---------------------------------------------------------------
|
|
A contrast ring sits under the accent ring so focus stays visible on both
|
|
light and dark surfaces, and on accent-filled controls. */
|
|
--nv-focus-ring-width: 3px;
|
|
--nv-focus-ring:
|
|
0 0 0 1px var(--nv-color-focus-ring-contrast),
|
|
0 0 0 calc(1px + var(--nv-focus-ring-width)) var(--nv-color-focus-ring);
|
|
|
|
/* --- Glow ------------------------------------------------------------------
|
|
Light a surface emits rather than the shade it casts. Glow is for things
|
|
that are *on* — a live status, the selected item in a showcase, a lit key —
|
|
and it always sits beside an elevation, never instead of one: a glowing
|
|
surface still rests on something.
|
|
|
|
The geometry is a scale like elevation. The color is the component's: a
|
|
tinted surface glows in its own tint, mixed down to --nv-glow-strength. */
|
|
--nv-glow-strength: 40%;
|
|
--nv-glow-blur-sm: 12px;
|
|
--nv-glow-spread-sm: -2px;
|
|
--nv-glow-blur-md: 28px;
|
|
--nv-glow-spread-md: -6px;
|
|
--nv-glow-blur-lg: 64px;
|
|
--nv-glow-spread-lg: -12px;
|
|
}
|
|
|
|
/* The accent glows are declared on every branded subtree as well as the root:
|
|
a var() inside a custom property resolves where the property is declared, so
|
|
a root-only declaration would glow in the root brand everywhere. */
|
|
:root,
|
|
[data-nv-brand] {
|
|
--nv-glow-sm: 0 0 var(--nv-glow-blur-sm) var(--nv-glow-spread-sm) var(--nv-color-glow);
|
|
--nv-glow-md: 0 0 var(--nv-glow-blur-md) var(--nv-glow-spread-md) var(--nv-color-glow);
|
|
--nv-glow-lg: 0 0 var(--nv-glow-blur-lg) var(--nv-glow-spread-lg) var(--nv-color-glow);
|
|
}
|