From ea238cf77d4af5c79113982ccccabd08bf3b8d34 Mon Sep 17 00:00:00 2001 From: Void Date: Tue, 10 Nov 2026 03:18:49 +0000 Subject: [PATCH] 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 --- src/app/features/scene/skyPlate.ts | 8 ++++++++ src/app/features/scene/skyTheme.test.ts | 19 ++++++++++++++++++- src/app/pages/auth/styles.css.ts | 23 +++++++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/app/features/scene/skyPlate.ts b/src/app/features/scene/skyPlate.ts index 872e2fd6..54ff13f2 100644 --- a/src/app/features/scene/skyPlate.ts +++ b/src/app/features/scene/skyPlate.ts @@ -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; diff --git a/src/app/features/scene/skyTheme.test.ts b/src/app/features/scene/skyTheme.test.ts index 53cf2873..dd46117b 100644 --- a/src/app/features/scene/skyTheme.test.ts +++ b/src/app/features/scene/skyTheme.test.ts @@ -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); + }); + } + ); +}); diff --git a/src/app/pages/auth/styles.css.ts b/src/app/pages/auth/styles.css.ts index b13bf868..c1614a79 100644 --- a/src/app/pages/auth/styles.css.ts +++ b/src/app/pages/auth/styles.css.ts @@ -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)', +});