UI polish batch: theme variants as submenus, bigger sidebar section headers, one overlay transparency with more-opaque inner cards, toasts above overlays #354

Closed
opened 2026-09-28 15:24:52 +00:00 by kayg · 19 comments
Owner

Owner (2026-09-28, screenshots):

  1. Theme picker: 'instead of adding a variant dropdown like this [Ayu ⌄] [Variant Ayu Dark ⌄], please add a sub-dropdown to existing items like Ayu > (Ayu Dark, Ayu Mirage)'. One Theme menu: families with variants show a chevron and open a submenu of their variants (shared Menu submenu support, keyboard ←/→, hover-intent). Remove the separate Variant control. The selected row shows the family + a check on the chosen variant. Families with one variant have no submenu.
  2. Sidebar section headers ('User', 'Admin', and every section header via the shared SidebarSectionHeader from #320): 'aren't big enough yet'. Raise them one step on the type scale with the medium/semibold weight token so they read as section headers, clearly above the rows; same across all sidebars.
  3. Overlays much more transparent, one value for all: 'the settings window itself should be way more transparent … applies to all overlays … just use the same transparency value in all overlays … the inner cards (sections) need to be a little less transparent than the overlay for the layered effect'. One overlay glass token used by every overlay (Settings, Admin, Analytics, the Inspector, sheets on desktop) at the same alpha as the floating glass from #289 (light 55% / dark 38%, blur + saturate), and one inner card token a step more opaque (≈ +12–15% alpha) for sections inside overlays. Keep the 4.5:1 text contrast contract (themes.test.ts), reduced transparency = opaque.
  4. Toasts render under overlays: 'when an overlay is opened, toasts seem to appear at the bottom view rather than at the top most view'. Toasts must always be in the top-most layer (above overlays, sheets, popovers, the scrim), using the shared portal/layer stack (#246); position them relative to the top-most surface's bottom capsule when one exists, else the viewport. Add an e2e: open Settings, trigger a toast (Copy link), assert it is visible and hit-testable above the overlay.
    Evidence at 390/820/1440, light and dark, including a background picture behind an overlay to judge transparency.
Owner (2026-09-28, screenshots): 1. **Theme picker:** 'instead of adding a variant dropdown like this [Ayu ⌄] [Variant Ayu Dark ⌄], please add a sub-dropdown to existing items like Ayu > (Ayu Dark, Ayu Mirage)'. One Theme menu: families with variants show a chevron and open a **submenu** of their variants (shared Menu submenu support, keyboard ←/→, hover-intent). Remove the separate Variant control. The selected row shows the family + a check on the chosen variant. Families with one variant have no submenu. 2. **Sidebar section headers** ('User', 'Admin', and every section header via the shared SidebarSectionHeader from #320): 'aren't big enough yet'. Raise them one step on the type scale with the medium/semibold weight token so they read as section headers, clearly above the rows; same across all sidebars. 3. **Overlays much more transparent, one value for all:** 'the settings window itself should be way more transparent … applies to all overlays … just use the same transparency value in all overlays … the inner cards (sections) need to be a little less transparent than the overlay for the layered effect'. One overlay glass token used by every overlay (Settings, Admin, Analytics, the Inspector, sheets on desktop) at the same alpha as the floating glass from #289 (light 55% / dark 38%, blur + saturate), and one **inner card** token a step more opaque (≈ +12–15% alpha) for sections inside overlays. Keep the 4.5:1 text contrast contract (themes.test.ts), reduced transparency = opaque. 4. **Toasts render under overlays:** 'when an overlay is opened, toasts seem to appear at the bottom view rather than at the top most view'. Toasts must always be in the top-most layer (above overlays, sheets, popovers, the scrim), using the shared portal/layer stack (#246); position them relative to the top-most surface's bottom capsule when one exists, else the viewport. Add an e2e: open Settings, trigger a toast (Copy link), assert it is visible and hit-testable above the overlay. Evidence at 390/820/1440, light and dark, including a background picture behind an overlay to judge transparency.
Author
Owner

Started on branch job/ui-polish-354 at base SHA 019c7abbc4.

Started on branch job/ui-polish-354 at base SHA 019c7abbc4c643f5a3fa3ef26723537bceb8f0de.
Author
Owner

Owner (2026-09-28, Calendar week on desktop): 'justification behind the black fade at the top of calendar on desktop?' Item 5: the shared --glass-header-wash (tokens.css:801) paints 72% → 40% of --paper from the top; in dark themes that is a near-black band even when nothing is scrolled under the header. Fix once for all mode headers: no tint at rest; when content is scrolled under the header, use the shared progressive blur (the same primitive as the Settings and search sticky headers) with at most a subtle tint in the glass base colour, fading in with the scroll. Readability is kept by the blur, not by darkening. Check Calendar Day/Week/Month, Files, Notes and Photos in light and dark with a background picture.

Owner (2026-09-28, Calendar week on desktop): 'justification behind the black fade at the top of calendar on desktop?' Item 5: the shared `--glass-header-wash` (tokens.css:801) paints 72% → 40% of `--paper` from the top; in dark themes that is a near-black band even when nothing is scrolled under the header. Fix once for all mode headers: **no tint at rest**; when content is scrolled under the header, use the shared **progressive blur** (the same primitive as the Settings and search sticky headers) with at most a subtle tint in the glass base colour, fading in with the scroll. Readability is kept by the blur, not by darkening. Check Calendar Day/Week/Month, Files, Notes and Photos in light and dark with a background picture.
Author
Owner

Starting implementation on job/ui-polish-354, based on 019c7abbc4c643f5a3fa3ef26723537bceb8f0de. Read the issue and newest comment (item 5); I am covering the shared theme menu, sidebar section header, glass tokens, toast layer, and mode header wash, with responsive light/dark evidence and the requested toast e2e.

Starting implementation on `job/ui-polish-354`, based on `019c7abbc4c643f5a3fa3ef26723537bceb8f0de`. Read the issue and newest comment (item 5); I am covering the shared theme menu, sidebar section header, glass tokens, toast layer, and mode header wash, with responsive light/dark evidence and the requested toast e2e.
Author
Owner

Scope addition (owner, 2026-09-28, screenshot of /analytics/week in dark): "all of these analytics cards need to be way more transparent!" The Analytics stat cards, the Added/By category/Habits cards and their inner tiles look nearly opaque. Fix through the shared tokens (--glass-card-alpha / --glass-card-bg in packages/ui/src/tokens.css), not per-component overrides: every page card (Analytics widgets under apps/web/src/lib/components/analytics, Settings cards, any .glass-card) uses the same transparency family as the overlays decided in this issue; inner tiles one step more opaque than their parent card. Check readability of numbers and labels on the busiest wallpaper in light and dark. Screenshots of /analytics/week at 390/820/1440 light and dark.

Scope addition (owner, 2026-09-28, screenshot of /analytics/week in dark): "all of these analytics cards need to be way more transparent!" The Analytics stat cards, the Added/By category/Habits cards and their inner tiles look nearly opaque. Fix through the shared tokens (`--glass-card-alpha` / `--glass-card-bg` in packages/ui/src/tokens.css), not per-component overrides: every page card (Analytics widgets under apps/web/src/lib/components/analytics, Settings cards, any .glass-card) uses the same transparency family as the overlays decided in this issue; inner tiles one step more opaque than their parent card. Check readability of numbers and labels on the busiest wallpaper in light and dark. Screenshots of /analytics/week at 390/820/1440 light and dark.
Author
Owner

Continuing on branch job/ui-polish-354 at base SHA 019c7abbc4. I have read the issue and all four comments; I am preserving the existing untracked ThemePicker test and implementing the added shared card transparency scope alongside the original UI polish items.

Continuing on branch job/ui-polish-354 at base SHA 019c7abbc4c643f5a3fa3ef26723537bceb8f0de. I have read the issue and all four comments; I am preserving the existing untracked ThemePicker test and implementing the added shared card transparency scope alongside the original UI polish items.
Author
Owner

Finding: the preserved ThemePicker regression test had an import path one directory short; after correcting the path, its current failure is the intended one: the Theme menu renders Ayu as a radio leaf, so the expected submenu is absent. The one-palette Paper row test passes.

Finding: the preserved ThemePicker regression test had an import path one directory short; after correcting the path, its current failure is the intended one: the Theme menu renders Ayu as a radio leaf, so the expected submenu is absent. The one-palette Paper row test passes.
Author
Owner

Finding: the preserved ThemePicker regression test had an import path one directory short. After correcting the path, its current failure is the intended one: the Theme menu renders Ayu as a radio leaf, so the expected submenu role menuitem is absent. The one-palette Paper row test passes.

Finding: the preserved ThemePicker regression test had an import path one directory short. After correcting the path, its current failure is the intended one: the Theme menu renders Ayu as a radio leaf, so the expected submenu role `menuitem` is absent. The one-palette Paper row test passes.
Author
Owner

Finding from source: packages/ui/src/components/Card.svelte painted --surface; Settings overrode its cards to the old --glass-card-bg; Analytics Added and Habits inner tiles used separate 18% and 34% hairline mixes. I changed the shared Card to the existing glass-card role, which now tracks the overlay alpha (55% light / 38% dark). Settings and the Analytics inner tiles use one shared role 14 points more opaque, within the requested 12–15 point step. The inner-tile hover uses a shared token, and the card role carries the soft glass text keyline for photo backgrounds. bun run test -- src/lib/themes.test.ts passes: 70 tests.

Finding from source: `packages/ui/src/components/Card.svelte` painted `--surface`; Settings overrode its cards to the old `--glass-card-bg`; Analytics Added and Habits inner tiles used separate 18% and 34% hairline mixes. I changed the shared Card to the existing `glass-card` role, which now tracks the overlay alpha (55% light / 38% dark). Settings and the Analytics inner tiles use one shared role 14 points more opaque, within the requested 12–15 point step. The inner-tile hover uses a shared token, and the card role carries the soft glass text keyline for photo backgrounds. `bun run test -- src/lib/themes.test.ts` passes: 70 tests.
Author
Owner

Issue #354 finding: OverlaySurface set its full-surface tint to --glass-scrim-bg, which resolves to 85% in light mode and 68% in dark mode. Floating glass and toast layers use the shared 55%/38% overlay role.

Change: full surfaces now use the same .glass-overlay role and shared text keyline. The scrim remains the separate page-dimming layer. The mode header wash uses the shared --glass-base at 8% and remains invisible until the header is scrolled.

Decision: use one --glass-alpha role for overlays and page cards; keep inner tiles one step more opaque (+14 points) as already recorded in the card finding.

Issue #354 finding: `OverlaySurface` set its full-surface tint to `--glass-scrim-bg`, which resolves to 85% in light mode and 68% in dark mode. Floating glass and toast layers use the shared 55%/38% overlay role. Change: full surfaces now use the same `.glass-overlay` role and shared text keyline. The scrim remains the separate page-dimming layer. The mode header wash uses the shared `--glass-base` at 8% and remains invisible until the header is scrolled. Decision: use one `--glass-alpha` role for overlays and page cards; keep inner tiles one step more opaque (+14 points) as already recorded in the card finding.
Author
Owner

Finding: the production evidence runner captured Analytics, the Theme menu and Settings toast without the requested photo wallpaper, and it did not cover all shared mode-header routes at 390/820/1440. I am extending it to upload the existing CC0 fixture through Files and capture those routes in both themes.

Finding: the production evidence runner captured Analytics, the Theme menu and Settings toast without the requested photo wallpaper, and it did not cover all shared mode-header routes at 390/820/1440. I am extending it to upload the existing CC0 fixture through Files and capture those routes in both themes.
Author
Owner

The first production capture exposed a fixture issue: the seven seeded dates crossed the Monday ISO-week boundary. The API report showed six entries in 2026-09-21..27 and one in 2026-09-28..10-04, so the screenshot route for the current week was mostly empty. I am changing the evidence runner to seed and capture the previous complete ISO week; this is not an Analytics product defect.

The first production capture exposed a fixture issue: the seven seeded dates crossed the Monday ISO-week boundary. The API report showed six entries in 2026-09-21..27 and one in 2026-09-28..10-04, so the screenshot route for the current week was mostly empty. I am changing the evidence runner to seed and capture the previous complete ISO week; this is not an Analytics product defect.
Author
Owner

Production capture found a shared overlay regression: /settings/appearance raised ReferenceError: glass is not defined before mounting. The production stack pointed to the OverlaySurface background; Svelte compiled the bare class:glass-overlay directive as an expression. I am moving that always-on class into the element's class attribute and will verify both Settings and the toast-over-Settings flow.

Production capture found a shared overlay regression: `/settings/appearance` raised `ReferenceError: glass is not defined` before mounting. The production stack pointed to the OverlaySurface background; Svelte compiled the bare `class:glass-overlay` directive as an expression. I am moving that always-on class into the element's `class` attribute and will verify both Settings and the toast-over-Settings flow.
Author
Owner

A later screenshot review showed that the UI uses the browser locale's Sunday week start, while the fixture readiness request used Analytics' Monday default. The dashboard therefore displayed Sep 27..Oct 3 with only Sep 27's entry even though the seeded entries filled Sep 21..27. I am capturing a stable seven-day Analytics window with an explicit from range and setting the readiness request's week_start to the same first day.

A later screenshot review showed that the UI uses the browser locale's Sunday week start, while the fixture readiness request used Analytics' Monday default. The dashboard therefore displayed Sep 27..Oct 3 with only Sep 27's entry even though the seeded entries filled Sep 21..27. I am capturing a stable seven-day Analytics window with an explicit `from` range and setting the readiness request's `week_start` to the same first day.
Author
Owner

The first full capture showed that localStorage alone did not hold the requested light scheme: authenticated appearance hydration replaced it with the account's saved dark mode (data-mode=dark, data-theme=midnight). I updated the production runner to save the scheme through /api/v1/appearance, reload, and assert the resolved mode before capturing each viewport. The corrected 55-image production matrix now passes, and the Analytics week shows all seven real fixture entries.

The first full capture showed that localStorage alone did not hold the requested light scheme: authenticated appearance hydration replaced it with the account's saved dark mode (`data-mode=dark`, `data-theme=midnight`). I updated the production runner to save the scheme through `/api/v1/appearance`, reload, and assert the resolved mode before capturing each viewport. The corrected 55-image production matrix now passes, and the Analytics week shows all seven real fixture entries.
Author
Owner

The production e2e/popovers.mjs run passed Calendar and Files, then stopped at its existing Search paint assertion (apps/web/e2e/popovers.mjs:137). That assertion reads .surface.search-window and expects glass-material plus glass-clear; the shared OverlaySurface now keeps the content wrapper transparent and puts its glass paint on the adjacent .surface-background (glass-overlay glass-clear). I left the assertion unchanged per the test rule. A separate real-server Settings Copy link check passed after hovering the Appearance heading: the toast was visible and hit-testable above Settings (toast z-index 1001, modal 21, opacity 1, pointer events enabled), and Settings stayed open.

The production `e2e/popovers.mjs` run passed Calendar and Files, then stopped at its existing Search paint assertion (`apps/web/e2e/popovers.mjs:137`). That assertion reads `.surface.search-window` and expects `glass-material` plus `glass-clear`; the shared `OverlaySurface` now keeps the content wrapper transparent and puts its glass paint on the adjacent `.surface-background` (`glass-overlay glass-clear`). I left the assertion unchanged per the test rule. A separate real-server Settings Copy link check passed after hovering the Appearance heading: the toast was visible and hit-testable above Settings (toast z-index 1001, modal 21, opacity 1, pointer events enabled), and Settings stayed open.
Author
Owner

The one full cargo test gate stopped in calternal-collab: 14 of 15 tests passed, while session::public_edit_limit_tests::ten_thousand_markdown_blocks_open_and_sync_within_two_seconds measured 2.305506525s against its 2s limit. Its phase timings were parse=1.38654889s, Yrs=576.011941ms, block-index=96.860778ms, first-sync=190.169161ms, snapshot=55.915755ms. Several other Cargo builds were active on the shared host. I did not change the expectation or rerun the full gate; this appears to be a load-sensitive timing failure, and the repository performance contract says performance is reviewed periodically rather than used as a merge gate.

The one full `cargo test` gate stopped in `calternal-collab`: 14 of 15 tests passed, while `session::public_edit_limit_tests::ten_thousand_markdown_blocks_open_and_sync_within_two_seconds` measured 2.305506525s against its 2s limit. Its phase timings were parse=1.38654889s, Yrs=576.011941ms, block-index=96.860778ms, first-sync=190.169161ms, snapshot=55.915755ms. Several other Cargo builds were active on the shared host. I did not change the expectation or rerun the full gate; this appears to be a load-sensitive timing failure, and the repository performance contract says performance is reviewed periodically rather than used as a merge gate.
Author
Owner

The first web check found three ThemePicker fixtures missing the required onselectvariant callback. I added no-op callbacks and bun run check then passed with svelte-check found 0 errors and 0 warnings; no assertions changed.

The full bun run test gate reported 747 passed and 4 failed. One dark ThemePicker test selected only menuitemradio rows, so it omitted the three variant-family parent menuitem rows. I changed the query to include both roles while keeping the expected 16-family list unchanged; the file passes 5/5. The other failures were 5-second timeouts in the sidebar-header, Analytics StatRow, and variant-submenu tests while several Cargo jobs were compiling. Targeted runs passed all three: SidebarSectionHeader + StatRow passed 17/17 and components/ThemePicker passed 2/2. The full suite was not rerun.

The first web check found three ThemePicker fixtures missing the required `onselectvariant` callback. I added no-op callbacks and `bun run check` then passed with `svelte-check found 0 errors and 0 warnings`; no assertions changed. The full `bun run test` gate reported 747 passed and 4 failed. One dark ThemePicker test selected only `menuitemradio` rows, so it omitted the three variant-family parent `menuitem` rows. I changed the query to include both roles while keeping the expected 16-family list unchanged; the file passes 5/5. The other failures were 5-second timeouts in the sidebar-header, Analytics StatRow, and variant-submenu tests while several Cargo jobs were compiling. Targeted runs passed all three: `SidebarSectionHeader` + `StatRow` passed 17/17 and `components/ThemePicker` passed 2/2. The full suite was not rerun.
Author
Owner

Final report

Implemented and pushed ui-polish-354 to origin/job/ui-polish-354.

Head: 2e84d4f37bf37a5b3d8aced3eac7d7720f491104

Built

  • Applied the shared glass role tokens to page cards and Analytics widgets, with the inner-card opacity roles preserved.
  • Fixed the shared overlay background class so Svelte does not evaluate glass as an undefined binding.
  • Expanded the real production-build visual runner to seed fixtures through the API and capture app views, theme menus, and the Copy link toast at 390, 820, and 1440 px in light and dark.
  • Updated ThemePicker test fixtures and its dark family-list selector without changing expected behavior.

Files

  • packages/ui/src/components/OverlaySurface.svelte
  • apps/web/e2e/ui-polish-354.mjs
  • apps/web/src/lib/themePicker.svelte.test.ts
  • apps/web/src/lib/components/ThemePicker.svelte.test.ts
  • apps/web/src/lib/menu-open-focus.svelte.test.ts

Commits: dd43ac5d, 04643c92, 958054a5, 2e84d4f3 (plus earlier 8d898a68).

Gates (captured output)

cargo fmt --check exited 0 with no output.

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

Finished `dev` profile [unoptimized + debuginfo] target(s) in 83m 20s

cargo test stopped in calternal-collab:

test session::public_edit_limit_tests::ten_thousand_markdown_blocks_open_and_sync_within_two_seconds ... FAILED
10,000-block collaboration phases: parse=1.38654889s, Yrs=576.011941ms, block-index=96.860778ms, first-sync=190.169161ms (616204 bytes), snapshot=55.915755ms (616199 bytes), total=2.305506525s

test result: FAILED. 14 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.55s
error: test failed, to rerun pass `-p calternal-collab --lib`

bun run check:

Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/ui-polish-354/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

The single full bun run test reported:

Test Files  4 failed | 110 passed (114)
      Tests  4 failed | 747 passed (751)

One failure was the dark ThemePicker family-list selector; its test now includes parent menuitem rows and passed in a focused 5/5 run. The other three tests timed out at 5 seconds under concurrent host load; focused runs later passed ThemePicker 2/2 and SidebarSectionHeader + StatRow 17/17. The full suite was not rerun.

Production screenshots:

PASS captured 55 production screenshots in /home/kayg/Developer/calternal-wt/ui-polish-354/artifacts/ui-polish-354

All 55 screenshots were uploaded to this issue. The one adversarial round was interrupted (exit 130) after the job crossed the four-hour limit. Findings captured before interruption were reported on #338 (Search misses during rebuild), #363 (undo/redo block spacing), #364 (delete/edit peer conflict), #368 (30-second file API timeouts), and #16 (10,000-block sync timing). The round did not complete. A separate bun e2e/popovers.mjs run stopped on its existing class assertion for .surface.search-window; the production Copy link toast check passed independently.

Decisions

No additional product decision was needed. I kept the shared overlay background as the paint owner and used the existing role tokens. The overlay class must be a literal Svelte class because the directive form treated glass as an undefined binding.

Production screenshot matrix (55 images; 390/820/1440 px, light/dark)

## Final report Implemented and pushed `ui-polish-354` to `origin/job/ui-polish-354`. **Head:** `2e84d4f37bf37a5b3d8aced3eac7d7720f491104` ### Built - Applied the shared glass role tokens to page cards and Analytics widgets, with the inner-card opacity roles preserved. - Fixed the shared overlay background class so Svelte does not evaluate `glass` as an undefined binding. - Expanded the real production-build visual runner to seed fixtures through the API and capture app views, theme menus, and the Copy link toast at 390, 820, and 1440 px in light and dark. - Updated ThemePicker test fixtures and its dark family-list selector without changing expected behavior. ### Files - `packages/ui/src/components/OverlaySurface.svelte` - `apps/web/e2e/ui-polish-354.mjs` - `apps/web/src/lib/themePicker.svelte.test.ts` - `apps/web/src/lib/components/ThemePicker.svelte.test.ts` - `apps/web/src/lib/menu-open-focus.svelte.test.ts` Commits: `dd43ac5d`, `04643c92`, `958054a5`, `2e84d4f3` (plus earlier `8d898a68`). ### Gates (captured output) `cargo fmt --check` exited 0 with no output. `cargo clippy --all-targets -- -D warnings`: ```text Finished `dev` profile [unoptimized + debuginfo] target(s) in 83m 20s ``` `cargo test` stopped in `calternal-collab`: ```text test session::public_edit_limit_tests::ten_thousand_markdown_blocks_open_and_sync_within_two_seconds ... FAILED 10,000-block collaboration phases: parse=1.38654889s, Yrs=576.011941ms, block-index=96.860778ms, first-sync=190.169161ms (616204 bytes), snapshot=55.915755ms (616199 bytes), total=2.305506525s test result: FAILED. 14 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.55s error: test failed, to rerun pass `-p calternal-collab --lib` ``` `bun run check`: ```text Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/ui-polish-354/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` The single full `bun run test` reported: ```text Test Files 4 failed | 110 passed (114) Tests 4 failed | 747 passed (751) ``` One failure was the dark ThemePicker family-list selector; its test now includes parent `menuitem` rows and passed in a focused 5/5 run. The other three tests timed out at 5 seconds under concurrent host load; focused runs later passed ThemePicker 2/2 and SidebarSectionHeader + StatRow 17/17. The full suite was not rerun. Production screenshots: ```text PASS captured 55 production screenshots in /home/kayg/Developer/calternal-wt/ui-polish-354/artifacts/ui-polish-354 ``` All 55 screenshots were uploaded to this issue. The one adversarial round was interrupted (exit 130) after the job crossed the four-hour limit. Findings captured before interruption were reported on #338 (Search misses during rebuild), #363 (undo/redo block spacing), #364 (delete/edit peer conflict), #368 (30-second file API timeouts), and #16 (10,000-block sync timing). The round did not complete. A separate `bun e2e/popovers.mjs` run stopped on its existing class assertion for `.surface.search-window`; the production Copy link toast check passed independently. ### Decisions No additional product decision was needed. I kept the shared overlay background as the paint owner and used the existing role tokens. The overlay class must be a literal Svelte class because the directive form treated `glass` as an undefined binding. ### Production screenshot matrix (55 images; 390/820/1440 px, light/dark) - [analytics-week-dark-1440.jpg](https://git.kayg.org/attachments/dde238d6-39b1-4d46-9f70-c009f687df1f) - [analytics-week-dark-390.jpg](https://git.kayg.org/attachments/e41600a4-afe3-401c-bb48-00e3b61f3fb6) - [analytics-week-dark-820.jpg](https://git.kayg.org/attachments/30f10d49-7ac6-4321-81d8-e85f6a99e93f) - [analytics-week-light-1440.jpg](https://git.kayg.org/attachments/dd68aa1b-7b55-4a58-8d98-1158842a5557) - [analytics-week-light-390.jpg](https://git.kayg.org/attachments/62655b7e-4dfa-4cb1-8d92-7b5c4a33bd0b) - [analytics-week-light-820.jpg](https://git.kayg.org/attachments/cc779217-861d-48f6-9669-17d62633ec38) - [calendar-day-dark-1440.jpg](https://git.kayg.org/attachments/4d3821b1-42c6-4810-ab5a-1db45c7594da) - [calendar-day-dark-390.jpg](https://git.kayg.org/attachments/5adbc6b7-41b5-42f7-bc4b-39f5f81ffd17) - [calendar-day-dark-820.jpg](https://git.kayg.org/attachments/27fc6849-c00f-4b21-abfb-4e51ca349eb4) - [calendar-day-light-1440.jpg](https://git.kayg.org/attachments/7e92946c-248c-4d92-bfe9-522db8dfdf29) - [calendar-day-light-390.jpg](https://git.kayg.org/attachments/808c39c5-43fc-4ece-b07f-02566fcb15ff) - [calendar-day-light-820.jpg](https://git.kayg.org/attachments/5f5f0570-b816-40f8-acc8-1d56567c9f77) - [calendar-month-dark-1440.jpg](https://git.kayg.org/attachments/5ec959f2-2b72-4048-bd91-9472a1b6561a) - [calendar-month-dark-390.jpg](https://git.kayg.org/attachments/46f0f478-288b-4187-b6ce-7bdc0210a483) - [calendar-month-dark-820.jpg](https://git.kayg.org/attachments/8f9a83bb-52f6-4f8e-9184-e004969cd40d) - [calendar-month-light-1440.jpg](https://git.kayg.org/attachments/e2d5fc33-16cc-49eb-b6f1-2789b7feb105) - [calendar-month-light-390.jpg](https://git.kayg.org/attachments/b4354d9c-1c50-4f28-869e-9ed1f9bac2b9) - [calendar-month-light-820.jpg](https://git.kayg.org/attachments/7d05a2e2-d86f-4d65-ac12-99a87f8eb743) - [calendar-week-dark-1440.jpg](https://git.kayg.org/attachments/87c0f704-c5db-4ffe-ab97-57814ae2ba0c) - [calendar-week-dark-390.jpg](https://git.kayg.org/attachments/4e9ea24a-7a72-4cf3-a5d2-e7d700fdca96) - [calendar-week-dark-820.jpg](https://git.kayg.org/attachments/aafdcf2b-e5a2-48b6-a662-090299aa5886) - [calendar-week-light-1440.jpg](https://git.kayg.org/attachments/88f7c7b5-e109-4bf6-b6fa-0041d96d7eaf) - [calendar-week-light-390.jpg](https://git.kayg.org/attachments/9064ad78-9886-44a2-aa87-027437a2af3c) - [calendar-week-light-820.jpg](https://git.kayg.org/attachments/ddae6b2d-1212-4d3f-93d0-aaf508eaa998) - [files-dark-1440.jpg](https://git.kayg.org/attachments/9d572a19-e5a4-4966-af21-bd6c83ab4e1c) - [files-dark-390.jpg](https://git.kayg.org/attachments/e57c34db-8b4d-40fa-af21-0f6c285ed278) - [files-dark-820.jpg](https://git.kayg.org/attachments/d38dd4f9-0a98-4d03-ba4d-4a094990555b) - [files-light-1440.jpg](https://git.kayg.org/attachments/800d898b-c12e-45cf-b9b2-5c7bb577c5a8) - [files-light-390.jpg](https://git.kayg.org/attachments/d2034ef4-77d8-49b0-9052-0dc4b9e17394) - [files-light-820.jpg](https://git.kayg.org/attachments/956cf09b-8a00-438f-a864-30c8742f9cc9) - [notes-dark-1440.jpg](https://git.kayg.org/attachments/6882bd8c-e6ce-4cfe-9de5-38879f0c2dad) - [notes-dark-390.jpg](https://git.kayg.org/attachments/8f844233-a9fa-4ef2-86c9-cc1c6b9a3998) - [notes-dark-820.jpg](https://git.kayg.org/attachments/a8afbf80-4bb7-4680-a937-5c4e3e2a3a8d) - [notes-light-1440.jpg](https://git.kayg.org/attachments/05e6a8a3-dad3-40ba-8926-972833832b09) - [notes-light-390.jpg](https://git.kayg.org/attachments/061316da-a60b-4256-b2f6-ecbd9628cca3) - [notes-light-820.jpg](https://git.kayg.org/attachments/9bee8cde-a6f8-4fb3-a42e-14ae9577d64d) - [photos-dark-1440.jpg](https://git.kayg.org/attachments/1064f51e-db83-4799-9d92-57107122dff3) - [photos-dark-390.jpg](https://git.kayg.org/attachments/eaffcb3e-30dd-4d1f-8640-0d8fe53236e4) - [photos-dark-820.jpg](https://git.kayg.org/attachments/09a23410-96f3-4268-b26c-8ab1e266acd8) - [photos-light-1440.jpg](https://git.kayg.org/attachments/f48855f8-8f3f-423d-8654-7684c7611867) - [photos-light-390.jpg](https://git.kayg.org/attachments/5e869ad3-9321-4246-b899-73e114113216) - [photos-light-820.jpg](https://git.kayg.org/attachments/2446d7a7-0de6-424f-ba92-d0b7190efc65) - [settings-copy-link-toast-dark-1440.jpg](https://git.kayg.org/attachments/38cb5f90-7fea-479e-84b4-270a87d84569) - [settings-copy-link-toast-dark-390.jpg](https://git.kayg.org/attachments/fe577409-49c1-4db4-b7da-87442f0c88d1) - [settings-copy-link-toast-dark-820.jpg](https://git.kayg.org/attachments/b68d288e-2f8a-47c9-aa5c-940d205f2508) - [settings-copy-link-toast-light-1440.jpg](https://git.kayg.org/attachments/1f2a02b7-d5de-4eb0-b5b4-5b553917f2cb) - [settings-copy-link-toast-light-390.jpg](https://git.kayg.org/attachments/839c9f24-c0ae-4642-ad2e-c6a07b4e080d) - [settings-copy-link-toast-light-820.jpg](https://git.kayg.org/attachments/413063dd-6b06-4a9f-b209-01065331cc41) - [settings-theme-menu-dark-1440.jpg](https://git.kayg.org/attachments/d8a23a2c-dbd3-4693-97b6-b6788b7d6983) - [settings-theme-menu-dark-390.jpg](https://git.kayg.org/attachments/aa08a3e7-2f03-4036-9e55-3d21ff4b3d26) - [settings-theme-menu-dark-820.jpg](https://git.kayg.org/attachments/3469c53d-68c2-4d11-b68e-b19dd492ae69) - [settings-theme-menu-light-1440.jpg](https://git.kayg.org/attachments/5b9fc3f5-445b-438b-ac1e-bcd4c6efa294) - [settings-theme-menu-light-390.jpg](https://git.kayg.org/attachments/baa44629-2cf4-478f-baf1-9b9e60b50d7d) - [settings-theme-menu-light-820.jpg](https://git.kayg.org/attachments/10c3fe52-4ba7-44fc-9d4f-a02b0631a557) - [settings-theme-submenu-dark-1440.jpg](https://git.kayg.org/attachments/69cc9796-0adf-474a-aef2-0aae48aefd34)
Author
Owner

Merged into dev by Claude after review; deployed to calternal.cloud. Closing.

Merged into dev by Claude after review; deployed to calternal.cloud. Closing.
kayg closed this issue 2026-09-29 00:53:16 +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#354
No description provided.