auth: a blurred, tinted, soft-edged band behind the sign-in footer line

The footer links sat on dark terrain in the sky's dark ink (contrast 1.0 to 2.9 at Dusk and
Day). The footer now carries the plate's ink over a backdrop-blur band tinted with the plate's
fill (FOOTER_TINT), faded at its edges; skyTheme.test.ts checks the ink over the darkest and
lightest scene behind it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Void 2026-11-10 03:18:49 +00:00
commit ea238cf77d
3 changed files with 49 additions and 1 deletions

View file

@ -7,3 +7,11 @@ export const SKY_PLATE_FALLBACK = {
text: '#b7c7d9',
link: '#99c7ff',
} as const;
/**
* The sign-in footer's tint: how much of the plate's fill (--sky-bubble) is mixed over the blurred scene behind the
* footer line. The footer is a blurred, tinted band with soft edges, not a plate: the scene shows through it. The
* footer ink is the plate's, so the tint has to bring the scene behind it to where that ink clears 4.5:1
* (skyTheme.test.ts).
*/
export const FOOTER_TINT = 0.75;

View file

@ -7,7 +7,7 @@ import { PageContent, PageNavContent } from '../../components/page/style.css';
import { CallStatus } from '../call-status/styles.css';
import { MembersDrawer } from '../room/MembersDrawer.css';
import { RoomViewTyping } from '../room/RoomViewTyping.css';
import { SKY_PLATE_FALLBACK } from './skyPlate';
import { FOOTER_TINT, SKY_PLATE_FALLBACK } from './skyPlate';
import { SkyPlate, plateRegions } from './skyPlate.css';
import { getResolvedSkyState, setSkyClock, skyBackdrop } from './skyState';
import type { SkyBackdrop } from './skyState';
@ -160,3 +160,20 @@ describe('regions that sit on the plate', () => {
expect(plateRegions.some((r) => r.includes(':not(:has('))).toBe(true);
});
});
describe('the sign-in footer band', () => {
// The footer line is the plate's ink on a band that mixes FOOTER_TINT of the plate's fill over the blurred scene.
// The scene behind it is the terrain: as dark as 0, as light as the sky state's lightest backdrop. Ink contrast is
// lowest at one of those two ends, so both are checked.
const tinted = (fill: string, behind: number) =>
FOOTER_TINT * luminance(fill) + (1 - FOOTER_TINT) * behind;
it.each(fixed)(
'%s: the ink clears AA over the darkest and the lightest scene behind it',
(state, id) => {
const { Other, OtherText } = SKY[id].bubbles;
[0, skyBackdrop(state).lightest].forEach((behind) => {
expect(against(OtherText, tinted(Other, behind))).toBeGreaterThanOrEqual(AA);
});
}
);
});

View file

@ -1,5 +1,6 @@
import { globalStyle, style } from '@vanilla-extract/css';
import { DefaultReset, color, config, toRem } from 'folds';
import { FOOTER_TINT } from '../../features/scene/skyPlate';
export const AuthLayout = style({
minHeight: '100%',
@ -88,3 +89,25 @@ globalStyle(`${scene} ${AuthCardContent}`, {
paddingBottom: config.space.S400,
gap: config.space.S500,
});
// The footer line sits on the terrain, which is dark at its foot in every sky (luminance 0.02 to 0.04 at dusk), where
// the sky's dark ink is unreadable. Over the scene it gets a blurred band tinted with the plate's fill and the plate's
// ink and link, faded out at its edges so it reads as haze and not as a bar: the scene shows through and round it.
// The tint (FOOTER_TINT) is checked against the ink in skyTheme.test.ts.
globalStyle(`${scene} ${AuthFooter}`, {
paddingTop: config.space.S500,
paddingBottom: config.space.S500,
backgroundColor: `color-mix(in srgb, var(--sky-bubble, #0d1a26) ${
FOOTER_TINT * 100
}%, transparent)`,
backdropFilter: 'blur(12px)',
WebkitBackdropFilter: 'blur(12px)',
maskImage:
'linear-gradient(to bottom, transparent, #000 16px, #000 calc(100% - 16px), transparent)',
WebkitMaskImage:
'linear-gradient(to bottom, transparent, #000 16px, #000 calc(100% - 16px), transparent)',
color: 'var(--sky-bubble-text, #b7c7d9)',
});
globalStyle(`${scene} ${AuthFooter} a`, {
color: 'var(--sky-bubble-text, #b7c7d9)',
});