From 1a23bd83a401cde63764481bea90a0247a8d4657 Mon Sep 17 00:00:00 2001 From: Garrett Mills Date: Mon, 26 Oct 2026 20:59:35 -0500 Subject: [PATCH] Pin list headers flush to the top of the scroll area Sticky headers pinned at the content area's padding edge, leaving a strip above them where scrolled-past rows showed through. Offset them by that padding. In grouped lists, column headers now pin below the sticky group heading instead of behind it. Closes #5 Co-Authored-By: Claude Opus 5.5 --- src/styles.css | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/styles.css b/src/styles.css index 9a009a4..38a21ee 100644 --- a/src/styles.css +++ b/src/styles.css @@ -774,9 +774,14 @@ input[type="checkbox"] { color: var(--warn); } .content { + /* Named so sticky headers can cancel it: sticky elements pin at the scroll + container's padding edge, which would leave a strip above them where + scrolled-past rows still show. */ + --content-pad-top: var(--space-5); + --group-header-h: 40px; flex: 1; overflow: auto; - padding: var(--space-5) var(--space-6); + padding: var(--content-pad-top) var(--space-6); } /* Empty / welcome state */ @@ -960,10 +965,18 @@ h4 { * tag) since h3 is also used for .dialog-title, which must not be sticky. */ .group-header { position: sticky; - top: 0; + top: calc(-1 * var(--content-pad-top, 0px)); z-index: 5; margin: var(--space-4) 0 var(--space-2); - padding: var(--space-2) 0; + /* A fixed height, so a grouped table's column headers can pin just below + it (see `.group-header + table th`). */ + height: var(--group-header-h); + box-sizing: border-box; + display: flex; + align-items: center; + gap: var(--space-2); + white-space: nowrap; + padding: 0; background: var(--bg-app); font-size: var(--fs-body); font-weight: 700; @@ -1569,7 +1582,7 @@ th { letter-spacing: var(--tracking-label); color: var(--muted); position: sticky; - top: 0; + top: calc(-1 * var(--content-pad-top, 0px)); background: var(--bg-content); border-bottom: 1px solid var(--border); z-index: 1; @@ -1579,6 +1592,10 @@ td { border-bottom: 1px solid var(--border-soft); vertical-align: middle; } +/* Under a sticky group header, pin below it instead of behind it. */ +.group-header + table th { + top: calc(var(--group-header-h) - var(--content-pad-top, 0px)); +} tbody tr { transition: background 0.08s; } @@ -3291,7 +3308,8 @@ button.pull-action { placement on Android). */ @media (max-width: 720px) { .content { - padding: var(--space-4); + --content-pad-top: var(--space-4); + padding: var(--content-pad-top); /* Clear the fixed bottom nav, or its last row of content is hidden behind it — the safe-area inset is already baked into the nav's own height, so it isn't added again here. */