Mobile: event card text touches borders; text sizes and spacing too dense #1083

Open
opened 2026-10-05 03:23:52 +00:00 by kayg · 13 comments
Owner

Owner report (2026-10-05 08:44–08:49 IST, iPhone, production 269b1b51b, dark theme). Screenshots: owner's four phone captures (Day view during horizontal swipe, Day view at rest, Settings → Account sheet, Agenda).

"Look at how text sizing, distance along UI elements and event cards; look at how the text in cards is touching the borders."

Day view event cards: text sits against the card edges (no inner padding on the left/top in the swiped card), line height and size are dense and inconsistent with the time chips; the title, tag chip and time chips have uneven spacing. Agenda rows: text became smaller than before.

Wanted: card content insets from spacing tokens on every side, one type scale (body for titles, caption for times/tags), consistent gaps between chips, title and tag; minimum tap sizes. Follow Apple HIG typography and layout for iOS (Dynamic Type sizes as reference: body 17 pt, subhead 15 pt, footnote 13 pt).

## Owner report (2026-10-05 08:44–08:49 IST, iPhone, production 269b1b51b, dark theme). Screenshots: owner's four phone captures (Day view during horizontal swipe, Day view at rest, Settings → Account sheet, Agenda). "Look at how text sizing, distance along UI elements and event cards; look at how the text in cards is touching the borders." Day view event cards: text sits against the card edges (no inner padding on the left/top in the swiped card), line height and size are dense and inconsistent with the time chips; the title, tag chip and time chips have uneven spacing. Agenda rows: text became smaller than before. Wanted: card content insets from spacing tokens on every side, one type scale (body for titles, caption for times/tags), consistent gaps between chips, title and tag; minimum tap sizes. Follow Apple HIG typography and layout for iOS (Dynamic Type sizes as reference: body 17 pt, subhead 15 pt, footnote 13 pt).
Author
Owner

Starting #1083 on branch job/cards-1083, based at 269b1b51b5 (dev production base). I am reviewing the supplied iPhone captures and the shared Calendar card components before changing Day, Week, Month and Agenda spacing.

Starting #1083 on branch job/cards-1083, based at 269b1b51b5774d79de08bfb31d058b3d248a7e7b (dev production base). I am reviewing the supplied iPhone captures and the shared Calendar card components before changing Day, Week, Month and Agenda spacing.
Author
Owner

Baseline finding from #1083: the supplied Day capture shows the title and tag inside a long card with little breathing room. In the shared CSS, Day/Week .block defaults to --text-caption (12px on touch), and .b-title inherits it; the card insets are only 6px inline and 3px block. Agenda .line uses --text-small (13px on touch) while its time is Caption (12px). Month rows are 21px high with 5px horizontal padding and no vertical padding. These values explain the size and spacing mismatch. I will use the existing Body and Caption roles plus spacing tokens across those surfaces, preserving the Month and time-grid touch exemptions already defined in DESIGN §34/§39.

Baseline finding from #1083: the supplied Day capture shows the title and tag inside a long card with little breathing room. In the shared CSS, Day/Week `.block` defaults to `--text-caption` (12px on touch), and `.b-title` inherits it; the card insets are only 6px inline and 3px block. Agenda `.line` uses `--text-small` (13px on touch) while its time is Caption (12px). Month rows are 21px high with 5px horizontal padding and no vertical padding. These values explain the size and spacing mismatch. I will use the existing Body and Caption roles plus spacing tokens across those surfaces, preserving the Month and time-grid touch exemptions already defined in DESIGN §34/§39.
Author
Owner

Complete

Head: 5c0d213ad64982aaaec337b81c51867bce7e967f

Commits:

  • 3fe2a4e2b — Improve Calendar card spacing on touch
  • 5c0d213ad — Add Calendar spacing capture coverage

Built

  • Added shared scaled spacing tokens for Calendar event content and chip gaps. Coarse pointers now use 8 px inline and 4 px block padding; fine-pointer desktop padding stays at the scaled 6 px by 3 px values.
  • Day and Week event titles use regular Body styling with 22 px line height when the block has room. Titles in blocks of 15 minutes or less keep Caption sizing to fit the duration-bound card. Times and tags use Caption styling.
  • Agenda titles use regular Body styling, shared spacing tokens, and 4 px chip gaps. Month rows use token padding on all sides, 4 px gaps, auto height, Body titles and Caption times.
  • Added production-build WebKit evidence coverage for Day, Week, Month and Agenda at 390, 430, 820 and 1440 px, in light and dark themes, with macOS platform labels.
  • Refreshed the perf-lint fingerprints in contracts/perf/registry.json and contracts/perf/exceptions.json after the component edits.

Files

  • packages/ui/src/tokens.css
  • packages/ui/src/components/calendar/AgendaList.svelte
  • packages/ui/src/components/calendar/GridColumn.svelte
  • packages/ui/src/components/calendar/MonthGrid.svelte
  • apps/web/e2e/cards-1083.mjs
  • contracts/perf/registry.json
  • contracts/perf/exceptions.json

UX gaps closed

  • Added comfortable event text insets on coarse pointers and consistent chip spacing.
  • Increased long event and Agenda title prominence while retaining Caption roles for times and tags.
  • Kept full event titles in accessible names when visual space requires line clamping or ellipsis.
  • Verified Agenda touch rows remain at least 44 px high on phone and tablet. Day/Week duration-bound cards and Month date-grid rows retain their existing documented hit-target exceptions.

UX gaps left

  • WebKit's Linux capture omits the painted Day/Week timed-card pixels, although the real Event button is present, visible by computed styles, has the expected geometry and accessible name, and its insets are measured. The standalone zoomed before/after crop is therefore the Agenda row; the Day/Week crop files are blank. A real Safari visual check is still needed before visual approval.
  • Narrow Month cells can still ellipsize a long title. The full title remains available to assistive technology and the row opens the item.
  • The screenshots show an Update available toast because the shared prebuilt server binary and this web build were produced from different revisions.

Screenshot evidence

The 390 px Day sample's CSS insets are 8 px left/right and 4 px top/bottom, compared with the previous 6 px by 3 px padding. Its title is 17 px with 22 px line height; time is 12 px and chip gap is 4 px. The E2E content-box measurement shows 4 px top and 8 px left/right; its 60.375 px bottom clearance is unused space inside the long event block, while the CSS bottom padding remains 4 px. At 1440 px, scaled padding is 6.42 px by 3.21 px and the Body title is 14.98 px. The zoom crop compares the Agenda row before and after.

Decisions (not specified in DESIGN)

  • Use 8 px by 4 px coarse-pointer event padding and a 4 px chip gap.
  • Use Body titles for longer Day/Week events, but preserve Caption sizing for events of 15 minutes or less so the text fits duration-bound blocks.
  • Keep Month titles ellipsized when the cell is too narrow and preserve the full accessible name.
  • Keep desktop insets scaled from the existing 6 px by 3 px values.

Gates

bun run check — exit 0. Exact summary output:

perf-lint: PASS; 0 violations; 18996 scoped exceptions
User browser caches use userStorage; only documented device/public-link exceptions remain.
Glass alpha, blur and backdrop-filter roles use packages/ui/src/tokens.css.
Text sizes and UI shape values use shared role tokens.
Keyboard focus rings use the shared focus tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
svelte-check found 0 errors and 4 warnings in 3 files

The four warnings are existing empty CSS rulesets in AttachmentDeck.svelte and AgendaList.svelte, plus two unused selectors in the Notes page.

Focused Vitest command: bunx vitest run src/lib/calendar/agenda.svelte.test.ts src/lib/calendar/MonthGrid.svelte.test.ts --maxWorkers=2

 RUN  v5.0.1 /home/kayg/Developer/calternal-wt/cards-1083/apps/web

 Test Files  2 passed (2)
      Tests  38 passed (38)
   Start at  06:50:49
   Duration  12.54s (transform 69%, tests 15%, environment 8%, import 6%, setup 2%)

Focused WebKit E2E command: bun apps/web/e2e/cards-1083.mjs

PASS #1083: 4 Calendar views × 4 widths × 2 themes in WebKit with macOS platform labels; screenshots and insets in /home/kayg/Developer/calternal-wt/cards-1083/artifacts/cards-1083

The fresh production web build completed (✓ built in 1m 10s). No Rust code changed, so Rust gates were not applicable. Full web suites and broader adversarial matrices remain for the merge round under the verification policy. cargo clean removed 8433 files (7.0 GiB); apps/web/build was deleted.

READY FOR MERGE: no — code and focused gates pass, but the Day/Week card pixel rendering needs visual confirmation in Safari.

## Complete **Head:** `5c0d213ad64982aaaec337b81c51867bce7e967f` **Commits:** - `3fe2a4e2b` — Improve Calendar card spacing on touch - `5c0d213ad` — Add Calendar spacing capture coverage ### Built - Added shared scaled spacing tokens for Calendar event content and chip gaps. Coarse pointers now use 8 px inline and 4 px block padding; fine-pointer desktop padding stays at the scaled 6 px by 3 px values. - Day and Week event titles use regular Body styling with 22 px line height when the block has room. Titles in blocks of 15 minutes or less keep Caption sizing to fit the duration-bound card. Times and tags use Caption styling. - Agenda titles use regular Body styling, shared spacing tokens, and 4 px chip gaps. Month rows use token padding on all sides, 4 px gaps, auto height, Body titles and Caption times. - Added production-build WebKit evidence coverage for Day, Week, Month and Agenda at 390, 430, 820 and 1440 px, in light and dark themes, with macOS platform labels. - Refreshed the perf-lint fingerprints in `contracts/perf/registry.json` and `contracts/perf/exceptions.json` after the component edits. ### Files - `packages/ui/src/tokens.css` - `packages/ui/src/components/calendar/AgendaList.svelte` - `packages/ui/src/components/calendar/GridColumn.svelte` - `packages/ui/src/components/calendar/MonthGrid.svelte` - `apps/web/e2e/cards-1083.mjs` - `contracts/perf/registry.json` - `contracts/perf/exceptions.json` ### UX gaps closed - Added comfortable event text insets on coarse pointers and consistent chip spacing. - Increased long event and Agenda title prominence while retaining Caption roles for times and tags. - Kept full event titles in accessible names when visual space requires line clamping or ellipsis. - Verified Agenda touch rows remain at least 44 px high on phone and tablet. Day/Week duration-bound cards and Month date-grid rows retain their existing documented hit-target exceptions. ### UX gaps left - WebKit's Linux capture omits the painted Day/Week timed-card pixels, although the real Event button is present, visible by computed styles, has the expected geometry and accessible name, and its insets are measured. The standalone zoomed before/after crop is therefore the Agenda row; the Day/Week crop files are blank. A real Safari visual check is still needed before visual approval. - Narrow Month cells can still ellipsize a long title. The full title remains available to assistive technology and the row opens the item. - The screenshots show an `Update available` toast because the shared prebuilt server binary and this web build were produced from different revisions. ### Screenshot evidence - [Before/after screenshot archive (all widths and themes, plus measurements and crop)](https://git.kayg.org/attachments/7a9bf39c-3a0a-4e5c-9736-9f8bd8e0839d) - [Zoomed Agenda row before/after crop](https://git.kayg.org/attachments/a7548dbf-4ad7-4195-9e4a-fc3551602c32) - [After measurements JSON](https://git.kayg.org/attachments/83ff9eff-5813-41a3-838d-9d498a1ec2e2) The 390 px Day sample's CSS insets are 8 px left/right and 4 px top/bottom, compared with the previous 6 px by 3 px padding. Its title is 17 px with 22 px line height; time is 12 px and chip gap is 4 px. The E2E content-box measurement shows 4 px top and 8 px left/right; its 60.375 px bottom clearance is unused space inside the long event block, while the CSS bottom padding remains 4 px. At 1440 px, scaled padding is 6.42 px by 3.21 px and the Body title is 14.98 px. The zoom crop compares the Agenda row before and after. ### Decisions (not specified in DESIGN) - Use 8 px by 4 px coarse-pointer event padding and a 4 px chip gap. - Use Body titles for longer Day/Week events, but preserve Caption sizing for events of 15 minutes or less so the text fits duration-bound blocks. - Keep Month titles ellipsized when the cell is too narrow and preserve the full accessible name. - Keep desktop insets scaled from the existing 6 px by 3 px values. ### Gates `bun run check` — exit 0. Exact summary output: ``` perf-lint: PASS; 0 violations; 18996 scoped exceptions User browser caches use userStorage; only documented device/public-link exceptions remain. Glass alpha, blur and backdrop-filter roles use packages/ui/src/tokens.css. Text sizes and UI shape values use shared role tokens. Keyboard focus rings use the shared focus tokens. UI transitions and animation options use shared motion tokens or documented exceptions. svelte-check found 0 errors and 4 warnings in 3 files ``` The four warnings are existing empty CSS rulesets in `AttachmentDeck.svelte` and `AgendaList.svelte`, plus two unused selectors in the Notes page. Focused Vitest command: `bunx vitest run src/lib/calendar/agenda.svelte.test.ts src/lib/calendar/MonthGrid.svelte.test.ts --maxWorkers=2` ``` RUN v5.0.1 /home/kayg/Developer/calternal-wt/cards-1083/apps/web Test Files 2 passed (2) Tests 38 passed (38) Start at 06:50:49 Duration 12.54s (transform 69%, tests 15%, environment 8%, import 6%, setup 2%) ``` Focused WebKit E2E command: `bun apps/web/e2e/cards-1083.mjs` ``` PASS #1083: 4 Calendar views × 4 widths × 2 themes in WebKit with macOS platform labels; screenshots and insets in /home/kayg/Developer/calternal-wt/cards-1083/artifacts/cards-1083 ``` The fresh production web build completed (`✓ built in 1m 10s`). No Rust code changed, so Rust gates were not applicable. Full web suites and broader adversarial matrices remain for the merge round under the verification policy. `cargo clean` removed 8433 files (7.0 GiB); `apps/web/build` was deleted. **READY FOR MERGE: no** — code and focused gates pass, but the Day/Week card pixel rendering needs visual confirmation in Safari.
Author
Owner

Starting capture/render investigation on job/cards-1083 at base 5c0d213ad6. Existing WebKit evidence shows the long Event in the DOM and in layout metrics while Day screenshots are blank; I am reproducing the paint state before deciding whether this is a capture race or a Safari-engine rendering regression.

Starting capture/render investigation on job/cards-1083 at base 5c0d213ad64982aaaec337b81c51867bce7e967f. Existing WebKit evidence shows the long Event in the DOM and in layout metrics while Day screenshots are blank; I am reproducing the paint state before deciding whether this is a capture race or a Safari-engine rendering regression.
Author
Owner

Finding: this is a Day/Week WebKit rendering regression, not a late Calendar response. In artifacts/cards-1083/after-measurements.json, the seeded 09:30–13:30 Event has full DOM text, visible CSS and non-zero bounds at 390 px, but elementFromPoint at its title returns the grid's .lanes layer in both themes and both Day/Week views. Its 3× crop is flat. The 1440 px captures also include off-viewport card bounds (Day light x=1000399; Week x=143274), so the capture helper needs to align and verify the real scrollport before it saves evidence. I am removing per-card content-visibility while retaining whole-column skipping, and adding an actual title hit-test to the production capture.

Finding: this is a Day/Week WebKit rendering regression, not a late Calendar response. In artifacts/cards-1083/after-measurements.json, the seeded 09:30–13:30 Event has full DOM text, visible CSS and non-zero bounds at 390 px, but elementFromPoint at its title returns the grid's .lanes layer in both themes and both Day/Week views. Its 3× crop is flat. The 1440 px captures also include off-viewport card bounds (Day light x=1000399; Week x=143274), so the capture helper needs to align and verify the real scrollport before it saves evidence. I am removing per-card content-visibility while retaining whole-column skipping, and adding an actual title hit-test to the production capture.
Author
Owner

Finding update: after removing content-visibility from the timed card itself, a fresh 390 px WebKit Day capture still showed no card paint even though the title hit test passed. The Week capture then stalled on Playwright’s default visible wait. This narrows the defect to the parent date column skip state and confirms the old capture check could pass on layout/hit testing alone. I am moving off-screen content-visibility to non-WebKit columns and making the capture assert actual title pixel variation before saving screenshots.

Finding update: after removing content-visibility from the timed card itself, a fresh 390 px WebKit Day capture still showed no card paint even though the title hit test passed. The Week capture then stalled on Playwright’s default visible wait. This narrows the defect to the parent date column skip state and confirms the old capture check could pass on layout/hit testing alone. I am moving off-screen content-visibility to non-WebKit columns and making the capture assert actual title pixel variation before saving screenshots.
Author
Owner

The WebKit rerun rules out the capture-wait explanation: on 390 px Day the real seeded title has an 88 px paint box, computed visibility visible and opacity 1, and the date column computes content-visibility: visible, but the title crop is uniform (luma 223–226). This is a rendering defect. I am isolating the remaining paint/containment interaction before the full screenshot matrix.

The WebKit rerun rules out the capture-wait explanation: on 390 px Day the real seeded title has an 88 px paint box, computed visibility visible and opacity 1, and the date column computes content-visibility: visible, but the title crop is uniform (luma 223–226). This is a rendering defect. I am isolating the remaining paint/containment interaction before the full screenshot matrix.
Author
Owner

Root cause found: GridColumn treated an undefined navigator during server rendering as a non-WebKit client, so SSR added skip-offscreen/content-visibility. Hydration later removed the class in WebKit, but fresh Safari-engine screenshots still had blank card pixels. Disabling paint containment and sticky positioning at runtime did not change the uniform title crop. I am changing SSR to start paintable and enabling off-screen skipping only after client platform detection.

Root cause found: GridColumn treated an undefined navigator during server rendering as a non-WebKit client, so SSR added skip-offscreen/content-visibility. Hydration later removed the class in WebKit, but fresh Safari-engine screenshots still had blank card pixels. Disabling paint containment and sticky positioning at runtime did not change the uniform title crop. I am changing SSR to start paintable and enabling off-screen skipping only after client platform detection.
Author
Owner

Correction from the next experiment: leaving the SSR column paintable was not sufficient. The decisive diagnostic showed nativeHorizontal=true, with .lane-track translated by the CSS scroll timeline at −307,000 px while the Event DOM stayed hit-testable. Freezing that same track offset to translateX(−scrollLeft) made the 390 px Day title pixels visible in both themes. The fix now routes WebKit through TimeGrid’s existing animation-frame offset fallback and keeps its mounted columns paintable; other engines retain the native timeline and off-screen skipping.

Correction from the next experiment: leaving the SSR column paintable was not sufficient. The decisive diagnostic showed nativeHorizontal=true, with .lane-track translated by the CSS scroll timeline at −307,000 px while the Event DOM stayed hit-testable. Freezing that same track offset to translateX(−scrollLeft) made the 390 px Day title pixels visible in both themes. The fix now routes WebKit through TimeGrid’s existing animation-frame offset fallback and keeps its mounted columns paintable; other engines retain the native timeline and off-screen skipping.
Author
Owner

Phone Week does not mount the narrow Event as a time-grid card: its 43–48 px day lanes are below the documented 64 px floor, so the real Event is grouped behind the 09:30 +1 control. The capture now taps that control and verifies the full Event title in the accessible shared list. This preserves the DESIGN §39 lane rule while keeping the title visible in the Week evidence.

Phone Week does not mount the narrow Event as a time-grid card: its 43–48 px day lanes are below the documented 64 px floor, so the real Event is grouped behind the 09:30 +1 control. The capture now taps that control and verifies the full Event title in the accessible shared list. This preserves the DESIGN §39 lane rule while keeping the title visible in the Week evidence.
Author
Owner

Gate finding: the first bun run check stopped in perf-lint because the merge kept origin/dev's AgendaList render.bound hash (61309070…), while this branch's AgendaList retains the #1083 card-spacing changes and matches the prior branch hash (30350185…). I am restoring the matching entry while keeping the newer origin/dev ledger, then I will rerun the requested gates.

Gate finding: the first bun run check stopped in perf-lint because the merge kept origin/dev's AgendaList render.bound hash (61309070…), while this branch's AgendaList retains the #1083 card-spacing changes and matches the prior branch hash (30350185…). I am restoring the matching entry while keeping the newer origin/dev ledger, then I will rerun the requested gates.
Author
Owner

Final report

READY FOR MERGE: yes

Branch: job/cards-1083
Base: 5c0d213ad64982aaaec337b81c51867bce7e967f
Merged origin/dev: b1664f0878313b35a647195e67a85cecf804a4e5
Head: 60fa353c51a5c8a8c0129a7ad21fa40ee2f59a17

Finding and fix

The blank Day capture was a production WebKit rendering bug, not a capture taken before the Event loaded. The Event title existed in the DOM and had a layout box, but the WebKit screenshot pixels were uniform while the native scroll timeline moved the long date track. Freezing the track at the same horizontal offset restored the title pixels.

TimeGrid now uses its existing animation-frame offset path in WebKit and keeps mounted date columns paintable. Other engines keep the native scroll timeline and off-screen column skipping. The virtual date window remains bounded. The E2E check now waits for the real Event, checks that its title pixels are painted, and then saves the capture.

Week columns under the 64 px lane floor use the existing +N action. The screenshot check taps it and confirms that the real Event title appears in the shared item list. At 1440 px the Event appears in the timed card.

UX gaps closed

  • Day and Week capture now proves that the long title is painted, rather than relying on DOM presence or a hit test alone.
  • The narrow Week overflow action is exercised by touch, and the shared list keeps the full Event title available to assistive technology.
  • The 390 px Day crop measures 4 px block padding and 8 px inline padding. The content inset is 4 px at the top and 8 px on both sides; the remaining bottom space is 60.38 px. The 3× crop is 876×570 px.

Screenshots and measurements

All 16 Day and Week screenshots use Playwright WebKit with macOS platform labels. They include the 09:30–13:30 long-title Event. The measurement JSON covers each view, width and theme.

Day

Width Light Dark
390 Day 390 light Day 390 dark
430 Day 430 light Day 430 dark
820 Day 820 light Day 820 dark
1440 Day 1440 light Day 1440 dark

Week

Width Light Dark
390 Week 390 light Week 390 dark
430 Week 430 light Week 430 dark
820 Week 820 light Week 820 dark
1440 Week 1440 light Week 1440 dark

3× Day card crop · All measured insets

Files and commits

  • packages/ui/src/components/calendar/TimeGrid.svelte: select the WebKit paint fallback.
  • packages/ui/src/components/calendar/GridColumn.svelte: keep WebKit columns paintable while preserving off-screen skipping in other engines.
  • apps/web/e2e/cards-1083.mjs: wait for painted Event text, exercise Week overflow, capture the requested matrix and measure the crop.
  • contracts/perf/exceptions.json and contracts/perf/adoption-1058.json: refresh exact syntax hashes after the merge. All 21,977 exception scopes and their limits remain unchanged; four adoption pins now match their live ledger rows.

Commits: f3d7727ce (performance pins), 60fa353c5 (WebKit rendering fix).

Gates

bun run check exited 0. Verbatim summary lines:

perf-lint: PASS; 0 violations; 21977 scoped exceptions
User browser caches use userStorage; only documented device/public-link exceptions remain.
Glass alpha, blur and backdrop-filter roles use packages/ui/src/tokens.css.
Text sizes and UI shape values use shared role tokens.
Keyboard focus rings use the shared focus tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
svelte-check found 0 errors and 4 warnings in 3 files

The four warnings are two empty CSS rulesets in AttachmentDeck.svelte and AgendaList.svelte, plus two unused CSS selectors in apps/web/src/routes/notes/+page.svelte (.note-page-lede and .note-state).

Test Files  2 passed (2)
     Tests  32 passed (32)
  Start at  09:57:02
  Duration  13.47s (transform 85%, import 5%, tests 5%, environment 4%, setup 1%)
PASS #1083: 2 Calendar views × 4 widths × 2 themes in WebKit with macOS platform labels; screenshots and insets in /home/kayg/Developer/calternal-wt/cards-1083/artifacts/cards-1083

Decisions and known gaps

  • WebKit uses the existing frame-offset fallback because the native scroll timeline moved the track without painting visible Event text. This keeps the fix within the existing bounded Day/Week grid.
  • The capture uses Playwright WebKit and emulated macOS platform labels. A native macOS Safari GUI run was not part of this job.
  • The existing calendar_grid profile covers the shared Calendar grid with real busy-week data. I did not run a performance measurement because #1083 is a paint-correctness issue and the verification policy limits performance measurements to performance issues.
## Final report **READY FOR MERGE: yes** Branch: `job/cards-1083` Base: `5c0d213ad64982aaaec337b81c51867bce7e967f` Merged `origin/dev`: `b1664f0878313b35a647195e67a85cecf804a4e5` Head: `60fa353c51a5c8a8c0129a7ad21fa40ee2f59a17` ### Finding and fix The blank Day capture was a production WebKit rendering bug, not a capture taken before the Event loaded. The Event title existed in the DOM and had a layout box, but the WebKit screenshot pixels were uniform while the native scroll timeline moved the long date track. Freezing the track at the same horizontal offset restored the title pixels. `TimeGrid` now uses its existing animation-frame offset path in WebKit and keeps mounted date columns paintable. Other engines keep the native scroll timeline and off-screen column skipping. The virtual date window remains bounded. The E2E check now waits for the real Event, checks that its title pixels are painted, and then saves the capture. Week columns under the 64 px lane floor use the existing `+N` action. The screenshot check taps it and confirms that the real Event title appears in the shared item list. At 1440 px the Event appears in the timed card. ### UX gaps closed - Day and Week capture now proves that the long title is painted, rather than relying on DOM presence or a hit test alone. - The narrow Week overflow action is exercised by touch, and the shared list keeps the full Event title available to assistive technology. - The 390 px Day crop measures 4 px block padding and 8 px inline padding. The content inset is 4 px at the top and 8 px on both sides; the remaining bottom space is 60.38 px. The 3× crop is 876×570 px. ### Screenshots and measurements All 16 Day and Week screenshots use Playwright WebKit with macOS platform labels. They include the 09:30–13:30 long-title Event. The measurement JSON covers each view, width and theme. **Day** | Width | Light | Dark | |---:|---|---| | 390 | [Day 390 light](https://git.kayg.org/attachments/bf85d96b-fcdd-48fa-8c23-adf190b1b767) | [Day 390 dark](https://git.kayg.org/attachments/6bd8042b-b894-4632-916c-267b95df574e) | | 430 | [Day 430 light](https://git.kayg.org/attachments/fbcd72f1-401b-4fa2-b141-d61d35d6f269) | [Day 430 dark](https://git.kayg.org/attachments/26673052-fb4b-47f1-86e3-42770244bf37) | | 820 | [Day 820 light](https://git.kayg.org/attachments/343b1d28-cf04-4b91-a3d7-3999156b885d) | [Day 820 dark](https://git.kayg.org/attachments/95f9bcbb-7173-44a6-9bb2-dca6d3ea7565) | | 1440 | [Day 1440 light](https://git.kayg.org/attachments/a583b308-7277-41bd-847e-75b57e24c898) | [Day 1440 dark](https://git.kayg.org/attachments/7147b2cc-787d-4a9e-9530-6005d9397131) | **Week** | Width | Light | Dark | |---:|---|---| | 390 | [Week 390 light](https://git.kayg.org/attachments/ce221640-5f47-4060-bae6-8170f24c2255) | [Week 390 dark](https://git.kayg.org/attachments/2f7703cb-2b19-4902-925b-8d537d60e109) | | 430 | [Week 430 light](https://git.kayg.org/attachments/17a95008-ac34-410c-a0f6-cf5620e2ff4b) | [Week 430 dark](https://git.kayg.org/attachments/0d0711f0-f586-478c-911e-f4417d173492) | | 820 | [Week 820 light](https://git.kayg.org/attachments/85fa3699-c234-4dfd-8a67-b2b2853b2962) | [Week 820 dark](https://git.kayg.org/attachments/697e3333-dbea-456c-b839-6e32ba589a19) | | 1440 | [Week 1440 light](https://git.kayg.org/attachments/1ff28196-d991-4a9c-afd4-91829c5a5582) | [Week 1440 dark](https://git.kayg.org/attachments/e8c8a8dd-328f-4bda-a563-748b1ebe3f09) | [3× Day card crop](https://git.kayg.org/attachments/367eee98-fae0-4fe6-9543-a4fbcbc53d42) · [All measured insets](https://git.kayg.org/attachments/c4dd7d9f-324c-45ee-b3e5-d020c277dc11) ### Files and commits - `packages/ui/src/components/calendar/TimeGrid.svelte`: select the WebKit paint fallback. - `packages/ui/src/components/calendar/GridColumn.svelte`: keep WebKit columns paintable while preserving off-screen skipping in other engines. - `apps/web/e2e/cards-1083.mjs`: wait for painted Event text, exercise Week overflow, capture the requested matrix and measure the crop. - `contracts/perf/exceptions.json` and `contracts/perf/adoption-1058.json`: refresh exact syntax hashes after the merge. All 21,977 exception scopes and their limits remain unchanged; four adoption pins now match their live ledger rows. Commits: `f3d7727ce` (performance pins), `60fa353c5` (WebKit rendering fix). ### Gates `bun run check` exited 0. Verbatim summary lines: ```text perf-lint: PASS; 0 violations; 21977 scoped exceptions User browser caches use userStorage; only documented device/public-link exceptions remain. Glass alpha, blur and backdrop-filter roles use packages/ui/src/tokens.css. Text sizes and UI shape values use shared role tokens. Keyboard focus rings use the shared focus tokens. UI transitions and animation options use shared motion tokens or documented exceptions. svelte-check found 0 errors and 4 warnings in 3 files ``` The four warnings are two empty CSS rulesets in `AttachmentDeck.svelte` and `AgendaList.svelte`, plus two unused CSS selectors in `apps/web/src/routes/notes/+page.svelte` (`.note-page-lede` and `.note-state`). ```text Test Files 2 passed (2) Tests 32 passed (32) Start at 09:57:02 Duration 13.47s (transform 85%, import 5%, tests 5%, environment 4%, setup 1%) ``` ```text PASS #1083: 2 Calendar views × 4 widths × 2 themes in WebKit with macOS platform labels; screenshots and insets in /home/kayg/Developer/calternal-wt/cards-1083/artifacts/cards-1083 ``` ### Decisions and known gaps - WebKit uses the existing frame-offset fallback because the native scroll timeline moved the track without painting visible Event text. This keeps the fix within the existing bounded Day/Week grid. - The capture uses Playwright WebKit and emulated macOS platform labels. A native macOS Safari GUI run was not part of this job. - The existing `calendar_grid` profile covers the shared Calendar grid with real busy-week data. I did not run a performance measurement because #1083 is a paint-correctness issue and the verification policy limits performance measurements to performance issues.
Author
Owner

UX gaps left

No remaining gap in the requested Day/Week flow. A native macOS Safari GUI session was not run; the requested Safari engine was checked with Playwright WebKit and macOS platform labels.

### UX gaps left No remaining gap in the requested Day/Week flow. A native macOS Safari GUI session was not run; the requested Safari engine was checked with Playwright WebKit and macOS platform labels.
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#1083
No description provided.