From 70ddc5e75391cf129cb5dc14e98a9aebeae013d6 Mon Sep 17 00:00:00 2001 From: Martin Dvorak Date: Tue, 13 Oct 2026 12:11:23 +0000 Subject: [PATCH] Ask pill joins the glass; Aero hovers light the pane, not move it The Ask button (and the two phone icon pills sharing its styling) was a hand-styled bg-[var(--surface-strong)] pill that never picked up the frosted recipe - it showed the sharp wallpaper through a flat tint while everything around it showed the blurred one. It carries a glass-pill class and is part of the same recipe now. Hover feedback: a transform or filter on a pane with a viewport-fixed backdrop re-anchors the glass, so the deck card's hover lift made the card flash a wrong crop of the wallpaper (and filter: brightness() on the buttons, plus the mobile :active scale foundation, would have done the same). Aero's feedback no longer moves or filters the glass: the pane lights up with an inner glow, a white rim and a deeper shadow over 170ms, and the pressed state shades inward. Contrast: 0 below-minimum findings, 0 axe violations. Version 0.3.3, SW -> freezmo-v64. --- README.md | 12 ++++++++ app/globals.css | 58 ++++++++++++++++++++++++++++++++++++ components/LibraryScreen.tsx | 6 ++-- package.json | 2 +- public/sw.js | 2 +- 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index abc2bb2..22e31e0 100644 --- a/README.md +++ b/README.md @@ -1411,6 +1411,18 @@ Things I chose while building, with the reasoning: pre-blurred wallpaper — the scene is clearly visible through the glass, and the pixel-contrast scan still passes. +68. **The Ask pill joins the glass, and Aero's hovers light the pane instead of moving it.** Two + leftovers from the previous pass. The Ask button (and the two phone icon pills that share its + styling) was a hand-styled `bg-[var(--surface-strong)]` pill that never picked up the frosted + recipe, so it showed the sharp wallpaper through a flat tint while everything around it showed + the blurred one — it carries a `glass-pill` class now and is part of the same recipe. And the + hover feedback: a `transform` or `filter` on a pane with a viewport-fixed backdrop re-anchors + the glass, so the deck card's hover lift made the card flash a wrong crop of the wallpaper + (and the buttons' `filter: brightness()` would have done the same, and the mobile + `:active { transform: scale(0.96) }` foundation made panes jump while pressed). Aero's + feedback never moves or filters the glass now: the pane lights up with an inner glow, a white + rim and a deeper shadow, transitioned over 170ms, and the pressed state shades inward. + 67. **The Aero wallpaper URL is cache-busted, and every surface is one glass.** Two fixes from one report. The background "didn't change" because the service worker's asset cache kept serving the previous wallpaper bytes (stale-while-revalidate returns the cached copy first, diff --git a/app/globals.css b/app/globals.css index 82ec22e..4565aa3 100644 --- a/app/globals.css +++ b/app/globals.css @@ -412,6 +412,7 @@ .aero .nav-row[aria-current="page"], .aero .nav-row[data-active="true"], .aero .glass-chip, +.aero .glass-pill, .aero .btn-secondary, .aero .btn-primary, .aero .grad-ice, @@ -443,6 +444,63 @@ box-shadow: 0 -14px 34px -22px rgb(2 62 110 / 0.5); } +/* Interactive glass feedback: a soft inner glow and a brighter rim on hover, + an inner shade while pressed. Deliberately no transform and no filter — on + a pane with a viewport-fixed backdrop either one re-anchors the glass and + it flashes a wrong crop of the wallpaper (the old hover lift did exactly + that to the deck cards). */ +.aero .nav-action, +.aero .nav-row, +.aero .glass-chip, +.aero .glass-pill, +.aero .btn-secondary, +.aero .btn-primary, +.aero .segmented > button, +.aero .segmented > a, +.aero .card-hover { + transition: box-shadow 170ms ease, border-color 170ms ease, background-color 170ms ease, color 170ms ease; +} +@media (hover: hover) and (pointer: fine) { + .aero .nav-action:hover, + .aero .nav-row:hover, + .aero .glass-chip:hover, + .aero .glass-pill:hover, + .aero .btn-secondary:hover, + .aero .btn-primary:hover, + .aero .segmented > button:hover, + .aero .segmented > a:hover, + .aero .card-hover:hover { + border-color: rgb(255 255 255 / 1); + background-color: rgb(255 255 255 / 0.34); + filter: none; + box-shadow: + 0 18px 38px -20px rgb(2 62 110 / 0.6), + inset 0 1px 0 rgb(255 255 255 / 1), + inset 0 0 30px rgb(255 255 255 / 0.55); + } + .aero .card-hover:hover { + transform: none; + } +} +.aero .card-hover:active, +.aero .card-hover:hover, +.aero .btn-primary:active, +.aero .segmented > button:active, +.aero .segmented > a:active, +.aero .nav-action:active, +.aero .glass-pill:active, +.aero .btn-secondary:active { + transform: none; + filter: none; +} +.aero .card-hover:active, +.aero .btn-primary:active, +.aero .nav-action:active, +.aero .glass-pill:active, +.aero .btn-secondary:active { + box-shadow: inset 0 2px 8px rgb(2 62 110 / 0.2), inset 0 1px 0 rgb(255 255 255 / 0.8); +} + /* The phone tab bar carries its labels right at the bottom of the water, so it keeps a little more veil than the cards. */ .aero .tabbar { diff --git a/components/LibraryScreen.tsx b/components/LibraryScreen.tsx index 2928493..99b28d1 100644 --- a/components/LibraryScreen.tsx +++ b/components/LibraryScreen.tsx @@ -203,7 +203,7 @@ export function LibraryScreen({ initialTab = "decks" }: { initialTab?: "decks" | {/* Desktop keeps Import above the tabs; phones get a small icon button in the tab row instead. */}
- + {t("chat.ask")} @@ -254,7 +254,7 @@ export function LibraryScreen({ initialTab = "decks" }: { initialTab?: "decks" | href="/chat" aria-label={t("chat.ask")} title={t("chat.ask")} - className="touch-target grid size-11 shrink-0 place-items-center rounded-2xl border border-[var(--glass-border)] bg-[var(--surface-strong)] text-[var(--text-muted)] transition hover:bg-[var(--hover)] hover:text-[var(--text)] sm:hidden" + className="glass-pill touch-target grid size-11 shrink-0 place-items-center rounded-2xl border border-[var(--glass-border)] bg-[var(--surface-strong)] text-[var(--text-muted)] transition hover:bg-[var(--hover)] hover:text-[var(--text)] sm:hidden" > @@ -263,7 +263,7 @@ export function LibraryScreen({ initialTab = "decks" }: { initialTab?: "decks" | onClick={() => setSheetOpen(true)} aria-label={t("library.moreActions")} title={t("library.moreActions")} - className="touch-target grid size-11 shrink-0 place-items-center rounded-2xl border border-[var(--glass-border)] bg-[var(--surface-strong)] text-[var(--text-muted)] transition hover:bg-[var(--hover)] hover:text-[var(--text)] sm:hidden" + className="glass-pill touch-target grid size-11 shrink-0 place-items-center rounded-2xl border border-[var(--glass-border)] bg-[var(--surface-strong)] text-[var(--text-muted)] transition hover:bg-[var(--hover)] hover:text-[var(--text)] sm:hidden" > diff --git a/package.json b/package.json index cc30079..9e5145c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "freezmo", - "version": "0.3.2", + "version": "0.3.3", "private": true, "license": "GPL-3.0-only", "scripts": { diff --git a/public/sw.js b/public/sw.js index 74bfcb4..262eba6 100644 --- a/public/sw.js +++ b/public/sw.js @@ -9,7 +9,7 @@ * * Bumping CACHE_VERSION is how a new deploy invalidates old assets. */ -const CACHE_VERSION = "freezmo-v63"; +const CACHE_VERSION = "freezmo-v64"; const SHELL_CACHE = `${CACHE_VERSION}-shell`; const ASSET_CACHE = `${CACHE_VERSION}-assets`;