GLASS: floating surfaces far more transparent so the blur visibly shows the content behind (keep 4.5:1 text) #289

Closed
opened 2026-09-28 06:12:31 +00:00 by kayg · 19 comments
Owner

Owner feedback (2026-09-28): "the blur is right for the dropdowns, etc but they need to be way more transparent! because right now they don't let me believe that it is truly blur and not a fake blur effect. i can't ever see if the background element is actually being blurred through the dropdowns, etc."

Scope: every floating surface that uses the shared portal + glass layer (#246): dropdown menus, context menus (e.g. the Files row menu), ⋯ menus, selects, popovers, the Search palette, tooltips, the inspector popover and toasts. It is ONE change in the shared glass tokens and the glass layer, not per-component edits (code reuse: one owner).

Target: the content behind a menu is clearly recognisable as blurred shapes and colours (an event block, a folder row, a photo). Today the tint is almost opaque.

  • Lower the tint alpha a lot. Start near 45–55 % in light and 40–50 % in dark, then tune from real screenshots. Keep or slightly raise the blur radius and add saturate() (Apple-style vibrancy, e.g. blur(24px) saturate(180%)) so colours read through.
  • Readability is a hard constraint (accessibility): menu text and shortcut glyphs must keep a WCAG contrast of 4.5:1 against the worst case behind them. Test on busy backgrounds: a Photos grid, a colourful Calendar week, and a custom background picture in both schemes. If the lower tint fails there, use a thin inner luminance layer or text-shadow hairline, not an opaque tint.
  • prefers-reduced-transparency: reduce (and the app's reduced-transparency setting if one exists) keeps the current opaque tint.
  • Browsers without backdrop-filter keep the opaque fallback.
  • One blur per stack stays the rule (the chart tooltip is the known exception).
  • Performance: measure the paint cost of an open menu over the Photos grid (Chrome trace, mid-range phone throttling) before and after. The blur radius must not add long tasks.

Evidence: 2× crops of a context menu over a Photos grid, a dropdown over a Calendar week, the Search palette over a background picture; light and dark; before and after; plus reduced transparency.

Owner feedback (2026-09-28): "the blur is right for the dropdowns, etc but they need to be way more transparent! because right now they don't let me believe that it is truly blur and not a fake blur effect. i can't ever see if the background element is actually being blurred through the dropdowns, etc." Scope: every floating surface that uses the shared portal + glass layer (#246): dropdown menus, context menus (e.g. the Files row menu), ⋯ menus, selects, popovers, the Search palette, tooltips, the inspector popover and toasts. It is ONE change in the shared glass tokens and the glass layer, not per-component edits (code reuse: one owner). Target: the content behind a menu is clearly recognisable as blurred shapes and colours (an event block, a folder row, a photo). Today the tint is almost opaque. - Lower the tint alpha a lot. Start near 45–55 % in light and 40–50 % in dark, then tune from real screenshots. Keep or slightly raise the blur radius and add `saturate()` (Apple-style vibrancy, e.g. `blur(24px) saturate(180%)`) so colours read through. - Readability is a hard constraint (accessibility): menu text and shortcut glyphs must keep a WCAG contrast of 4.5:1 against the worst case behind them. Test on busy backgrounds: a Photos grid, a colourful Calendar week, and a custom background picture in both schemes. If the lower tint fails there, use a thin inner luminance layer or text-shadow hairline, not an opaque tint. - `prefers-reduced-transparency: reduce` (and the app's reduced-transparency setting if one exists) keeps the current opaque tint. - Browsers without `backdrop-filter` keep the opaque fallback. - One blur per stack stays the rule (the chart tooltip is the known exception). - Performance: measure the paint cost of an open menu over the Photos grid (Chrome trace, mid-range phone throttling) before and after. The blur radius must not add long tasks. Evidence: 2× crops of a context menu over a Photos grid, a dropdown over a Calendar week, the Search palette over a background picture; light and dark; before and after; plus reduced transparency.
Author
Owner

Starting #289 on branch job/glass, based on dev at 8778fd00a6. I am checking the shared glass tokens/layer and production UI paths before making the single shared-surface change.

Starting #289 on branch job/glass, based on dev at 8778fd00a6d390085d1672fe6ca1915c449aea60. I am checking the shared glass tokens/layer and production UI paths before making the single shared-surface change.
Author
Owner

Code finding: the shared overlay token is 42% in light and 44% in dark, but the clear role used by Search is 71%/50%, and floating surfaces above a scrim use 85%/68% (packages/ui/src/tokens.css). I am checking the actual rendered surfaces before changing the shared roles.

Code finding: the shared overlay token is 42% in light and 44% in dark, but the clear role used by Search is 71%/50%, and floating surfaces above a scrim use 85%/68% (`packages/ui/src/tokens.css`). I am checking the actual rendered surfaces before changing the shared roles.
Author
Owner

Production baseline and implementation finding: opening a top-level float moves it to the 85% light / 68% dark --glass-scrim-alpha role in scrim.css; Search and clear surfaces use 71% light / 50% dark. The 85% / 68% role also paints full Settings sheets, so reducing it globally fails the existing 4.5:1 sheet contrast check. I have split the shared token role: transient floats and toasts use 55% / 45% above a scrim, while full sheets keep the existing tint. The initial 4× CPU trace on the Photos grid recorded 74.53 ms across Paint/RasterTask events (longest 6.12 ms), plus 14 RunTask trace events and 10 browser LongTask entries during the capture window; I will repeat it after the change with the same capture flow.

Production baseline and implementation finding: opening a top-level float moves it to the 85% light / 68% dark `--glass-scrim-alpha` role in `scrim.css`; Search and clear surfaces use 71% light / 50% dark. The 85% / 68% role also paints full Settings sheets, so reducing it globally fails the existing 4.5:1 sheet contrast check. I have split the shared token role: transient floats and toasts use 55% / 45% above a scrim, while full sheets keep the existing tint. The initial 4× CPU trace on the Photos grid recorded 74.53 ms across Paint/RasterTask events (longest 6.12 ms), plus 14 RunTask trace events and 10 browser LongTask entries during the capture window; I will repeat it after the change with the same capture flow.
Author
Owner

The photo-safe tint and shared contrast checks pass. The final two-edge keyline capture produced 255.10 ms total Paint/RasterTask (77 events, 43.29 ms longest) and 15 trace tasks over 50 ms; the earlier baseline capture was 74.53 ms (68 events, 6.12 ms longest) and 14. The trace is SLOW-only and variable: it starts after Photos tiles exist, so image work can continue, and this host is shared. The blur radius did not change. I am attaching the final production captures next; keyline paint was reduced from eight edges to two. Targeted suite: 68 tests passed.

The photo-safe tint and shared contrast checks pass. The final two-edge keyline capture produced 255.10 ms total Paint/RasterTask (77 events, 43.29 ms longest) and 15 trace tasks over 50 ms; the earlier baseline capture was 74.53 ms (68 events, 6.12 ms longest) and 14. The trace is SLOW-only and variable: it starts after Photos tiles exist, so image work can continue, and this host is shared. The blur radius did not change. I am attaching the final production captures next; keyline paint was reduced from eight edges to two. Targeted suite: 68 tests passed.
Author
Owner

Production reduced-transparency capture exposed a dark-mode cascade defect: the light Photos menu, Calendar dropdown and Search palette all compute backdrop-filter: none, but the dark Photos menu still computes a filter. The dark .glass-overlay rule has higher specificity than the reduced-transparency rule, so it restores blur in dark mode. I am fixing the selector precedence and will rerun the dark reduced capture.

Production reduced-transparency capture exposed a dark-mode cascade defect: the light Photos menu, Calendar dropdown and Search palette all compute `backdrop-filter: none`, but the dark Photos menu still computes a filter. The dark `.glass-overlay` rule has higher specificity than the reduced-transparency rule, so it restores blur in dark mode. I am fixing the selector precedence and will rerun the dark reduced capture.
Author
Owner
Production-build evidence is attached. Captures use real Photos, Calendar and Search data at 2×. The reduced-transparency run checked the computed filter on each open surface: all six report `none`. **Before** - [Photos context, light](https://git.kayg.org/attachments/ede9ae8e-fd62-4847-920f-60e6fe128b90) - [Calendar dropdown, light](https://git.kayg.org/attachments/0e29049b-3a69-47d0-9ec7-786a83cb7dbf) - [Search palette, light](https://git.kayg.org/attachments/84b3103c-b2c3-4381-9834-03c25ee2dd9d) - [Photos context, dark](https://git.kayg.org/attachments/d72afe72-89e8-424b-9e51-9ba267a31c46) - [Calendar dropdown, dark](https://git.kayg.org/attachments/eb5d51e4-5f5f-4f86-988c-8d8cfd1ce7a4) - [Search palette, dark](https://git.kayg.org/attachments/b9b5dfda-94a6-4806-aaab-7ded3184d6c9) **After** - [Photos context, light](https://git.kayg.org/attachments/9e262946-8158-495b-8fd8-e412e80ae368) - [Calendar dropdown, light](https://git.kayg.org/attachments/75cd1758-1ee8-4395-ba74-6162389b90da) - [Search palette, light](https://git.kayg.org/attachments/d23c15d9-7ab1-4c52-99c1-c333c839952b) - [Photos context, dark](https://git.kayg.org/attachments/bbbe4567-f69b-48fa-ad7d-01db95fe82e6) - [Calendar dropdown, dark](https://git.kayg.org/attachments/91abdaf4-b521-4410-91cd-ce85a7d799f2) - [Search palette, dark](https://git.kayg.org/attachments/ffe77d61-8bd3-4609-ae29-1d787a5727d3) **Reduced transparency** - [Photos context, light](https://git.kayg.org/attachments/401e9a5e-6b1e-432e-86d2-68dfe0837016) - [Calendar dropdown, light](https://git.kayg.org/attachments/60bca06e-3dba-42af-991e-c2bd1e3f9777) - [Search palette, light](https://git.kayg.org/attachments/8485b5b6-73ef-40bc-a827-4535423dbad5) - [Photos context, dark](https://git.kayg.org/attachments/8cb0ccb6-0397-4196-8807-1cdaa2911d0c) - [Calendar dropdown, dark](https://git.kayg.org/attachments/fc826c7e-61be-4f23-a56c-ae0bfb2488ae) - [Search palette, dark](https://git.kayg.org/attachments/2a41e504-3dcd-48f9-a3c5-5d96cbe3a592)
Author
Owner

One SLOW-only finding from the local adversarial round: after the 20,000-file watcher fixture, the route-complete authz matrix's Guest-share upload setup returned status -1. Its HTTP helper has a 20-second socket timeout. The preceding Search chaos probe passed but logged search-index queue-full warnings during the fixture churn. The server remained available for the later editor probes, which passed their nested-Markdown and 10,000-block cases. I am recording this as load-sensitive; no 5xx or crash has appeared in this round so far.

One SLOW-only finding from the local adversarial round: after the 20,000-file watcher fixture, the route-complete authz matrix's Guest-share upload setup returned status `-1`. Its HTTP helper has a 20-second socket timeout. The preceding Search chaos probe passed but logged search-index queue-full warnings during the fixture churn. The server remained available for the later editor probes, which passed their nested-Markdown and 10,000-block cases. I am recording this as load-sensitive; no 5xx or crash has appeared in this round so far.
Author
Owner

The non-SLOW editor text-loss finding is filed as #314 with the adversarial seed, failing round-trip, and expected/actual text. It is in the merged editor history path and outside this glass job's owned files. The one local adversarial round is continuing to cover the remaining probes.

The non-SLOW editor text-loss finding is filed as [#314](https://git.kayg.org/kayg/calternal/issues/314) with the adversarial seed, failing round-trip, and expected/actual text. It is in the merged editor history path and outside this glass job's owned files. The one local adversarial round is continuing to cover the remaining probes.
Author
Owner

Additional SLOW-only observation from the same local adversarial round: DAV incremental sync timed out during the attack. The server then served the calendar query and multiget at 207 in 9.3s and 8.8s. No 5xx or process exit was observed; this is recorded as load-sensitive.

Additional SLOW-only observation from the same local adversarial round: DAV incremental sync timed out during the attack. The server then served the calendar query and multiget at 207 in 9.3s and 8.8s. No 5xx or process exit was observed; this is recorded as load-sensitive.
Author
Owner

The single adversarial round reached its 30-minute cap during calendar Log this occurrence 0 first write, which returned no response before the probe's timeout. The runner removed its temporary server and data on exit. Search chaos, Calendar Event tag validation, duplicate-account checks, and the Photos tag/upload probes had passed; Photos uploads returned 201/204. The authz fixture upload had also timed out under the earlier 20,000-file watcher load, and the editor text-loss issue is tracked in #314. This leaves the final calendar log idempotency, media, and round-2 probes incomplete. These are recorded as load-sensitive probe timeouts; no 5xx or server crash was observed before the time cap.

The single adversarial round reached its 30-minute cap during `calendar Log this occurrence 0 first write`, which returned no response before the probe's timeout. The runner removed its temporary server and data on exit. Search chaos, Calendar Event tag validation, duplicate-account checks, and the Photos tag/upload probes had passed; Photos uploads returned 201/204. The authz fixture upload had also timed out under the earlier 20,000-file watcher load, and the editor text-loss issue is tracked in #314. This leaves the final calendar log idempotency, media, and round-2 probes incomplete. These are recorded as load-sensitive probe timeouts; no 5xx or server crash was observed before the time cap.
Author
Owner

Completed and pushed job/glass.

Head: a4b7de628cdc6bd6fce384251154e62267cd65ea (includes the one requested merge of dev). The remote branch resolves to the same SHA. The worktree is clean.

Built

  • Floating glass tint is 55% in light themes and 45% in dark themes across the shared glass roles. Full sheets keep their denser 85%/68% tint. Dark floating glass continues to dim its sampled backdrop to 65%, with the existing 16 px blur and 1.5 saturation.
  • A shared opposing black/white 0.5 px text keyline protects copy over bright and dark photo pixels. Contrast checks cover all 36 themes and retain the 4.5:1 target.
  • Reduced transparency uses opaque surfaces and disables glass filtering in both schemes. Dark-specific selectors now preserve the user preference over the more specific dark blur rules. The no-backdrop-filter fallback remains near-opaque.
  • Top-level float surfaces and toasts above scrims use the shared float tint. The design decision is recorded in docs/DESIGN.md §35.

Files changed for #289

  • packages/ui/src/tokens.css
  • packages/ui/src/themes.css
  • packages/ui/src/components/menu/FloatingSurface.svelte
  • apps/web/src/lib/styles/scrim.css
  • apps/web/src/lib/components/AppToaster.svelte
  • apps/web/src/lib/themes.test.ts
  • docs/DESIGN.md

All 18 requested 2× production crops are attached and linked in the evidence comment above: Photos context menu, Calendar dropdown, and Search palette in light, dark, and reduced-transparency modes.

Gates

  • cargo fmt --check: exit 0; no output.

  • cargo clippy --all-targets -- -D warnings:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 8m 30s
    
  • cargo test:

    Finished `test` profile [unoptimized + debuginfo] target(s) in 4m 33s
    

    The 72 test result lines total 1,355 passed, 0 failed, and 12 ignored.

  • bun run check:

    svelte-check found 0 errors and 0 warnings
    
  • bun run test:

     Test Files  107 passed (107)
          Tests  702 passed (702)
       Duration  72.30s (transform 57%, environment 17%, import 14%, tests 9%, setup 3%)
    
  • Focused theme suite after the dark reduced-transparency fix: 69 tests passed.

  • Merged production bun run build completed and wrote apps/web/build. cargo clean removed 14.7 GiB; apps/web/build and apps/web/.svelte-kit were then removed as requested.

Performance and adversarial findings

The one 4× CPU paint trace over Photos measured 74.53 ms Paint/RasterTask total before and 255.10 ms after (68 vs 77 events; longest 6.12 ms vs 43.29 ms). Trace tasks over 50 ms were 14 before and 15 after. The blur radius did not change. This single shared-host trace starts after the Photos tiles exist, while image work can continue, so it does not isolate the glass paint cost; the Paint/Raster result is a performance gap for follow-up review.

The single local adversarial round reached its 30-minute cap during a timed-out Calendar Log write. Search chaos, Calendar Event tag validation, duplicate-account checks, and Photos tag/upload probes passed. Some later reads and fixture uploads were SLOW under the 20,000-file watcher load; the authz fixture upload and DAV incremental sync also timed out. No 5xx or server crash appeared before the cap. Final calendar Log idempotency, media, and round-2 probes did not complete.

The editor adversarial probe found note text loss after hostile paste, IME, block actions, and undo/redo. I filed it as #314, kept the existing expectation unchanged, and left editor files outside this job untouched.

Decisions

  • Use 55%/45% for shared floating surfaces, inside the owner’s requested ranges, while preserving denser full-sheet tint.
  • Use two opposing 0.5 px luminance shadows for the text keyline. They maintain a black and a white edge with less shadow work than the initial eight-edge draft.
  • Keep the existing 16 px blur and 1.5 saturation. Repository search found no separate app-level reduced-transparency setting, so the browser prefers-reduced-transparency media query is the preference hook.
Completed and pushed `job/glass`. **Head:** `a4b7de628cdc6bd6fce384251154e62267cd65ea` (includes the one requested merge of `dev`). The remote branch resolves to the same SHA. The worktree is clean. ## Built - Floating glass tint is 55% in light themes and 45% in dark themes across the shared glass roles. Full sheets keep their denser 85%/68% tint. Dark floating glass continues to dim its sampled backdrop to 65%, with the existing 16 px blur and 1.5 saturation. - A shared opposing black/white 0.5 px text keyline protects copy over bright and dark photo pixels. Contrast checks cover all 36 themes and retain the 4.5:1 target. - Reduced transparency uses opaque surfaces and disables glass filtering in both schemes. Dark-specific selectors now preserve the user preference over the more specific dark blur rules. The no-`backdrop-filter` fallback remains near-opaque. - Top-level float surfaces and toasts above scrims use the shared float tint. The design decision is recorded in `docs/DESIGN.md` §35. ## Files changed for #289 - `packages/ui/src/tokens.css` - `packages/ui/src/themes.css` - `packages/ui/src/components/menu/FloatingSurface.svelte` - `apps/web/src/lib/styles/scrim.css` - `apps/web/src/lib/components/AppToaster.svelte` - `apps/web/src/lib/themes.test.ts` - `docs/DESIGN.md` All 18 requested 2× production crops are attached and linked in the evidence comment above: Photos context menu, Calendar dropdown, and Search palette in light, dark, and reduced-transparency modes. ## Gates - `cargo fmt --check`: exit 0; no output. - `cargo clippy --all-targets -- -D warnings`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 8m 30s ``` - `cargo test`: ```text Finished `test` profile [unoptimized + debuginfo] target(s) in 4m 33s ``` The 72 `test result` lines total 1,355 passed, 0 failed, and 12 ignored. - `bun run check`: ```text svelte-check found 0 errors and 0 warnings ``` - `bun run test`: ```text Test Files 107 passed (107) Tests 702 passed (702) Duration 72.30s (transform 57%, environment 17%, import 14%, tests 9%, setup 3%) ``` - Focused theme suite after the dark reduced-transparency fix: 69 tests passed. - Merged production `bun run build` completed and wrote `apps/web/build`. `cargo clean` removed 14.7 GiB; `apps/web/build` and `apps/web/.svelte-kit` were then removed as requested. ## Performance and adversarial findings The one 4× CPU paint trace over Photos measured 74.53 ms Paint/RasterTask total before and 255.10 ms after (68 vs 77 events; longest 6.12 ms vs 43.29 ms). Trace tasks over 50 ms were 14 before and 15 after. The blur radius did not change. This single shared-host trace starts after the Photos tiles exist, while image work can continue, so it does not isolate the glass paint cost; the Paint/Raster result is a performance gap for follow-up review. The single local adversarial round reached its 30-minute cap during a timed-out Calendar Log write. Search chaos, Calendar Event tag validation, duplicate-account checks, and Photos tag/upload probes passed. Some later reads and fixture uploads were SLOW under the 20,000-file watcher load; the authz fixture upload and DAV incremental sync also timed out. No 5xx or server crash appeared before the cap. Final calendar Log idempotency, media, and round-2 probes did not complete. The editor adversarial probe found note text loss after hostile paste, IME, block actions, and undo/redo. I filed it as [#314](https://git.kayg.org/kayg/calternal/issues/314), kept the existing expectation unchanged, and left editor files outside this job untouched. ## Decisions - Use 55%/45% for shared floating surfaces, inside the owner’s requested ranges, while preserving denser full-sheet tint. - Use two opposing 0.5 px luminance shadows for the text keyline. They maintain a black and a white edge with less shadow work than the initial eight-edge draft. - Keep the existing 16 px blur and 1.5 saturation. Repository search found no separate app-level reduced-transparency setting, so the browser `prefers-reduced-transparency` media query is the preference hook.
Author
Owner

Orchestrator review of a4b7de62 (2026-09-28): light: approved. The Photos context menu shows the photos clearly through the glass and the text stays readable. Dark: not done. The before/after dark crops (Photos context, Calendar dropdown) are almost identical: dark floating glass still applies a backdrop brightness of 0.65 on top of the 45% tint, so the backdrop reads as nearly opaque. The owner's complaint was exactly the dark dropdowns ('i can't ever see if the background element is actually being blurred').
Changes needed:

  1. Dark: raise the backdrop brightness to about 0.85–0.9 (or remove it) and tune the tint (try 35–40%) until the Photos grid and the Calendar events are clearly recognisable through a dark menu. Keep 4.5:1 through the keyline (it already exists) and the per-theme contrast tests. Show the dark crops side by side with the light ones; the effect must be of similar strength.
  2. Performance: the trace shows Paint/Raster at 74.5 ms before vs 255.1 ms after over Photos. That trace mixed in photo work, so rerun it isolated: the same scroll position, thumbnails fully loaded and idle, a menu opened 5× in each build, interleaved, with the medians reported. If the increase is real, find which filter in the chain costs the most (blur vs saturate vs brightness vs the keyline text-shadow on every row) and fix it. For example, move the keyline to a single cheaper paint, or drop brightness(), which also fixes point 1. The target is no more than +15% paint time versus before.
  3. The pointer-opened menu shows 'Open' highlighted; that belongs to #287 (item 4). Do not fix it here.
    Keep the scope to the glass tokens and FloatingSurface. Run the gates, merge dev, push, and attach new dark crops plus the isolated trace numbers.
Orchestrator review of a4b7de62 (2026-09-28): **light: approved.** The Photos context menu shows the photos clearly through the glass and the text stays readable. **Dark: not done.** The before/after dark crops (Photos context, Calendar dropdown) are almost identical: dark floating glass still applies a backdrop brightness of 0.65 on top of the 45% tint, so the backdrop reads as nearly opaque. The owner's complaint was exactly the dark dropdowns ('i can't ever see if the background element is actually being blurred'). Changes needed: 1. Dark: raise the backdrop brightness to about 0.85–0.9 (or remove it) and tune the tint (try 35–40%) until the Photos grid and the Calendar events are clearly recognisable through a dark menu. Keep 4.5:1 through the keyline (it already exists) and the per-theme contrast tests. Show the dark crops side by side with the light ones; the effect must be of similar strength. 2. **Performance:** the trace shows Paint/Raster at 74.5 ms before vs 255.1 ms after over Photos. That trace mixed in photo work, so rerun it isolated: the same scroll position, thumbnails fully loaded and idle, a menu opened 5× in each build, interleaved, with the medians reported. If the increase is real, find which filter in the chain costs the most (blur vs saturate vs brightness vs the keyline text-shadow on every row) and fix it. For example, move the keyline to a single cheaper paint, or drop brightness(), which also fixes point 1. The target is no more than +15% paint time versus before. 3. The pointer-opened menu shows 'Open' highlighted; that belongs to #287 (item 4). Do not fix it here. Keep the scope to the glass tokens and FloatingSurface. Run the gates, merge dev, push, and attach new dark crops plus the isolated trace numbers.
Author
Owner

Continuing the orchestrator review on branch job/glass at a4b7de628c; dev is c99fc31dd9. I am reducing the dark backdrop dimming, capturing matched light/dark production crops, and repeating the Photos paint trace with thumbnails idle and five interleaved menu opens per build.

Continuing the orchestrator review on branch job/glass at a4b7de628cdc6bd6fce384251154e62267cd65ea; dev is c99fc31dd9e0f542a02956a787010bbf1250384c. I am reducing the dark backdrop dimming, capturing matched light/dark production crops, and repeating the Photos paint trace with thumbnails idle and five interleaved menu opens per build.
Author
Owner

Implementation finding: dark glass inherited brightness(0.65) on overlay and clear surfaces. It is removed; all 20 dark palette tint tokens plus shared clear and above-scrim roles are now 38%. The shared keyline and 16px blur/1.5 saturation remain. Focused theme contrast suite: 69 passed. Committed as d7063600; I am building matched production servers and preparing the isolated interleaved trace.

Implementation finding: dark glass inherited brightness(0.65) on overlay and clear surfaces. It is removed; all 20 dark palette tint tokens plus shared clear and above-scrim roles are now 38%. The shared keyline and 16px blur/1.5 saturation remain. Focused theme contrast suite: 69 passed. Committed as d7063600; I am building matched production servers and preparing the isolated interleaved trace.
Author
Owner

Trace setup finding: debug loads from disk; the before and candidate Rust executable SHA-256 values were both 90237fa7b7432a08bda6ba974b3019a434c575d07bcec88d6f811bb395620f94. The first two interleaved samples therefore did not compare distinct frontend builds and are discarded. I am capturing separate production SPA bundles on one server/browser, swapping the bundle before each measured open.

Trace setup finding: debug loads from disk; the before and candidate Rust executable SHA-256 values were both 90237fa7b7432a08bda6ba974b3019a434c575d07bcec88d6f811bb395620f94. The first two interleaved samples therefore did not compare distinct frontend builds and are discarded. I am capturing separate production SPA bundles on one server/browser, swapping the bundle before each measured open.
Author
Owner

Correction to the trace setup note: in the debug test profile, calternal-server loads the SPA from apps/web/build on disk. The before and candidate Rust executable SHA-256 values were both 90237fa7b7432a08bda6ba974b3019a434c575d07bcec88d6f811bb395620f94. The first two interleaved samples compared the same frontend build and are discarded. I am now alternating separately built SPA bundles on one server and browser before each measured menu open.

Correction to the trace setup note: in the debug test profile, calternal-server loads the SPA from apps/web/build on disk. The before and candidate Rust executable SHA-256 values were both 90237fa7b7432a08bda6ba974b3019a434c575d07bcec88d6f811bb395620f94. The first two interleaved samples compared the same frontend build and are discarded. I am now alternating separately built SPA bundles on one server and browser before each measured menu open.
Author
Owner

Trace and dark glass update:

  • Dark glass now uses a 38% tint and no longer dims the sampled backdrop with brightness(0.65). The two-edge text keyline stays in place to preserve contrast.
  • The isolated Photos trace used 8 real API-uploaded photos with decoded thumbnails, scrollY 0, a 2x viewport, 4x CPU throttling, one server/browser, and five alternating openings per bundle.
  • FloatingSurface Paint median: 4.365 ms before, 3.360 ms after (−23.0%). RasterTask median: 23.603 ms before, 14.837 ms after (−37.1%). Scoped Paint + raster median: 26.086 ms before, 23.589 ms after (−9.6%); the median of the five interleaved paired deltas is −36.5%. This does not show a real increase above the +15% target.
  • Page-wide Paint median rose from 10.704 ms to 15.266 ms (+42.6%). This includes document and other layer paints. The attached trace report keeps this figure visible; the component-scoped Paint and raster work decreased.
  • Focused theme test passed: 69 tests.

Photos context menus

Palette Before After
Light before light Photos context menu after light Photos context menu
Dark before dark Photos context menu after dark Photos context menu

Calendar dropdowns

Palette Before After
Light before light Calendar dropdown after light Calendar dropdown
Dark before dark Calendar dropdown after dark Calendar dropdown

Isolated trace medians and paired samples

Trace and dark glass update: - Dark glass now uses a 38% tint and no longer dims the sampled backdrop with `brightness(0.65)`. The two-edge text keyline stays in place to preserve contrast. - The isolated Photos trace used 8 real API-uploaded photos with decoded thumbnails, scrollY 0, a 2x viewport, 4x CPU throttling, one server/browser, and five alternating openings per bundle. - FloatingSurface Paint median: 4.365 ms before, 3.360 ms after (−23.0%). RasterTask median: 23.603 ms before, 14.837 ms after (−37.1%). Scoped Paint + raster median: 26.086 ms before, 23.589 ms after (−9.6%); the median of the five interleaved paired deltas is −36.5%. This does not show a real increase above the +15% target. - Page-wide Paint median rose from 10.704 ms to 15.266 ms (+42.6%). This includes document and other layer paints. The attached trace report keeps this figure visible; the component-scoped Paint and raster work decreased. - Focused theme test passed: 69 tests. **Photos context menus** | Palette | Before | After | |---|---|---| | Light | ![before light Photos context menu](https://git.kayg.org/attachments/ddd79f49-a716-47cc-b21b-988221793cde) | ![after light Photos context menu](https://git.kayg.org/attachments/17a9b2cd-13f6-4c27-b4af-278362de84c6) | | Dark | ![before dark Photos context menu](https://git.kayg.org/attachments/5351c194-6aab-4530-bb06-02c9a8b72a83) | ![after dark Photos context menu](https://git.kayg.org/attachments/43d2b2f4-466a-4837-b95a-9da3f28e945b) | **Calendar dropdowns** | Palette | Before | After | |---|---|---| | Light | ![before light Calendar dropdown](https://git.kayg.org/attachments/9762741b-11a5-4ac6-97d1-1b0884efda94) | ![after light Calendar dropdown](https://git.kayg.org/attachments/67d1a390-457b-4822-a86e-695fe371e1e1) | | Dark | ![before dark Calendar dropdown](https://git.kayg.org/attachments/4d5d811c-f795-414a-8d6d-3f9e1097393b) | ![after dark Calendar dropdown](https://git.kayg.org/attachments/7a6f50c5-6985-48f7-8a19-621b10e6cf06) | [Isolated trace medians and paired samples](https://git.kayg.org/attachments/fc443b52-9d19-4d14-bf73-54cf667625af)
Author
Owner

The single post-merge adversarial round found a non-SLOW availability failure in the Search rebuild and watcher-overflow probe. The old Index stopped returning a live hit, the local API proxy returned repeated 502 responses because the server was unavailable, and restart-ready-4 did not appear within 180 seconds. The runner stopped at this point, so later probe groups did not run. The shared host was also running separate large Search and adversarial workloads, which leaves the cause inconclusive. I filed the evidence and a request for an isolated reproduction in #325. The runner removed its temporary logs during cleanup.

The single post-merge adversarial round found a non-SLOW availability failure in the Search rebuild and watcher-overflow probe. The old Index stopped returning a live hit, the local API proxy returned repeated 502 responses because the server was unavailable, and `restart-ready-4` did not appear within 180 seconds. The runner stopped at this point, so later probe groups did not run. The shared host was also running separate large Search and adversarial workloads, which leaves the cause inconclusive. I filed the evidence and a request for an isolated reproduction in [#325](https://git.kayg.org/kayg/calternal/issues/325). The runner removed its temporary logs during cleanup.
Author
Owner

Completed #289 on job/glass.

Built

  • Changed dark glass tint from 45% to 38% across shared roles and all dark theme palettes.
  • Removed brightness(0.65) from dark glass. The 16px blur, 1.5 saturation, and two-edge text keyline remain.
  • Updated the glass contrast model and focused theme test.
  • Attached before/after Light and Dark Photos and Calendar crops, plus the interleaved trace medians, in the earlier comments on this issue.

Files

  • packages/ui/src/tokens.css
  • packages/ui/src/themes.css
  • apps/web/src/lib/themes.test.ts

Trace

The Photos trace used real API-uploaded files and decoded thumbnails at scrollY 0, a 2x viewport, 4x CPU throttling, one server/browser and five alternating menu openings per bundle.

  • FloatingSurface Paint median: 4.365 ms before, 3.360 ms after (−23.0%).
  • RasterTask median: 23.603 ms before, 14.837 ms after (−37.1%).
  • Scoped Paint + raster median: 26.086 ms before, 23.589 ms after (−9.6%). Median paired delta: −36.5%.
  • Whole-page Paint median: 10.704 ms before, 15.266 ms after (+42.6%). This includes document, scrim and tile Paint events; the attached JSON reports it separately.

Gates

  • cargo fmt --check: no output; exit 0.
  • cargo clippy --all-targets -- -D warnings:
    Finished \dev` profile [unoptimized + debuginfo] target(s) in 3m 39s`
  • cargo test: passed across the workspace. Final unit-suite output:
    test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.17s
    Final doc-test output:
    test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
  • bun run check:
    svelte-check found 0 errors and 0 warnings
  • bun run test:
    Test Files 110 passed (110)
    Tests 710 passed (710)
    Start at 11:39:02
    Duration 55.40s (transform 58%, environment 17%, import 14%, tests 8%, setup 3%)

Known gap

The single post-merge adversarial run stopped in Search chaos. During a staged rebuild, the old Index lost a live hit and the local proxy returned repeated 502 responses because the server was unavailable. The restart-ready-4 marker did not arrive within 180 seconds. Other large Search and adversarial workloads were running on the shared host, so the cause is inconclusive. The runner removed its temporary logs and did not run later probe groups. I filed this evidence and an isolated-reproduction request as #325.

Decisions

  • Chose 38% for dark tint, within the requested 35–40% range. The existing text keyline carries contrast without dimming the sampled backdrop.
  • Kept the shared blur and saturation because the isolated FloatingSurface Paint and raster measurements did not show a regression above 15%.

Branch

  • job/glass head: bb174bcedc4b779424a4cb27e3e0bafa809c20db
  • git push origin job/glass: Everything up-to-date
  • cargo clean: Removed 17696 files, 15.8GiB total
Completed #289 on `job/glass`. ## Built - Changed dark glass tint from 45% to 38% across shared roles and all dark theme palettes. - Removed `brightness(0.65)` from dark glass. The 16px blur, 1.5 saturation, and two-edge text keyline remain. - Updated the glass contrast model and focused theme test. - Attached before/after Light and Dark Photos and Calendar crops, plus the interleaved trace medians, in the earlier comments on this issue. ## Files - `packages/ui/src/tokens.css` - `packages/ui/src/themes.css` - `apps/web/src/lib/themes.test.ts` ## Trace The Photos trace used real API-uploaded files and decoded thumbnails at scrollY 0, a 2x viewport, 4x CPU throttling, one server/browser and five alternating menu openings per bundle. - FloatingSurface Paint median: 4.365 ms before, 3.360 ms after (−23.0%). - RasterTask median: 23.603 ms before, 14.837 ms after (−37.1%). - Scoped Paint + raster median: 26.086 ms before, 23.589 ms after (−9.6%). Median paired delta: −36.5%. - Whole-page Paint median: 10.704 ms before, 15.266 ms after (+42.6%). This includes document, scrim and tile Paint events; the attached JSON reports it separately. ## Gates - `cargo fmt --check`: no output; exit 0. - `cargo clippy --all-targets -- -D warnings`: `Finished \`dev\` profile [unoptimized + debuginfo] target(s) in 3m 39s` - `cargo test`: passed across the workspace. Final unit-suite output: `test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.17s` Final doc-test output: `test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s` - `bun run check`: `svelte-check found 0 errors and 0 warnings` - `bun run test`: `Test Files 110 passed (110)` `Tests 710 passed (710)` `Start at 11:39:02` `Duration 55.40s (transform 58%, environment 17%, import 14%, tests 8%, setup 3%)` ## Known gap The single post-merge adversarial run stopped in Search chaos. During a staged rebuild, the old Index lost a live hit and the local proxy returned repeated 502 responses because the server was unavailable. The `restart-ready-4` marker did not arrive within 180 seconds. Other large Search and adversarial workloads were running on the shared host, so the cause is inconclusive. The runner removed its temporary logs and did not run later probe groups. I filed this evidence and an isolated-reproduction request as [#325](https://git.kayg.org/kayg/calternal/issues/325). ## Decisions - Chose 38% for dark tint, within the requested 35–40% range. The existing text keyline carries contrast without dimming the sampled backdrop. - Kept the shared blur and saturation because the isolated FloatingSurface Paint and raster measurements did not show a regression above 15%. ## Branch - `job/glass` head: `bb174bcedc4b779424a4cb27e3e0bafa809c20db` - `git push origin job/glass`: `Everything up-to-date` - `cargo clean`: `Removed 17696 files, 15.8GiB total`
kayg closed this issue 2026-09-28 10:41:23 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#289
No description provided.