From 0e3cafc5c6ecc15f9ee21ebe342cc91cd58299c5 Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Wed, 11 Nov 2026 18:23:54 +1100 Subject: [PATCH 1/2] fix(staged): phone Settings panels scroll under the home indicator; finger-sized controls On a phone the Settings panels were cards inset 14px from the page with the bottom safe-area inset added to the page's padding, so each panel's scrolling body stopped 48px above the screen's bottom edge and a band of chrome sat under the home indicator instead of content scrolling beneath it. In the phone layout the card is now dropped (no border, radius or page padding) and the inset moves into the panel body's own bottom padding via `--settings-panel-inset-bottom`, so General, Keyboard and Doctor scroll to the screen's edge and under the indicator. The Repos panel's repo detail does the same by moving the inset from the panel's padding to its scroller's. Touch targets on coarse pointers: the Settings tabs grow from 32px to 44px tall; Doctor's Copy details / Re-run buttons to 36px (matching the Keyboard panel's shortcut actions); diff file-tree rows from 26px to 36px and the Mark-as-reviewed toggle from 20px to 32px square, growing within its row so a tap just outside a row still lands on the neighbouring row. The project-status rows' name field keeps a readable width on a phone (flex-basis 160px) so the seven 30px colour swatches wrap under it instead of squeezing it to about 48px ("In prog", "Polishi"). Verified in an iOS 27.2 simulator (iPhone, software keyboard) in both Mobile Safari and Home Screen mode. The three originally reported bugs (double bottom inset in the note chat, opaque inset band while scrolling, taps above the keyboard not firing) were already fixed on main by #1043 and re-verified there. Signed-off-by: Matt Toohey Co-Authored-By: Claude Fable 5.1 Signed-off-by: Matt Toohey --- .../features/diff/DiffFileTreeSection.svelte | 16 ++++++++++++ .../settings/ActionsSettingsPanel.svelte | 10 +++++++ .../settings/DoctorSettingsPanel.svelte | 10 +++++++ .../settings/GeneralSettingsPanel.svelte | 2 ++ .../settings/KeyboardSettingsPanel.svelte | 2 ++ .../ProjectStatusOptionsSetting.svelte | 7 +++++ .../lib/features/settings/SettingsPage.svelte | 26 ++++++++++++++++++- 7 files changed, 72 insertions(+), 1 deletion(-) diff --git a/apps/staged/src/lib/features/diff/DiffFileTreeSection.svelte b/apps/staged/src/lib/features/diff/DiffFileTreeSection.svelte index bf0f55e60..f031e5e92 100644 --- a/apps/staged/src/lib/features/diff/DiffFileTreeSection.svelte +++ b/apps/staged/src/lib/features/diff/DiffFileTreeSection.svelte @@ -598,6 +598,22 @@ color: var(--status-added); } + /* Finger-sized rows and review toggles on a touch screen: the rows are + 26px tall at their padding and the toggle 20px square. The toggle grows + within its row rather than past it, so a tap just above or below a row + still reaches the neighbouring row and not this row's toggle. */ + @media (pointer: coarse) { + .tree-item { + min-height: 36px; + } + + .status-icon { + width: 32px; + height: 32px; + margin: -2px -6px; + } + } + .status-icon-static { cursor: default; } diff --git a/apps/staged/src/lib/features/settings/ActionsSettingsPanel.svelte b/apps/staged/src/lib/features/settings/ActionsSettingsPanel.svelte index 5020dfe37..5b955dab6 100644 --- a/apps/staged/src/lib/features/settings/ActionsSettingsPanel.svelte +++ b/apps/staged/src/lib/features/settings/ActionsSettingsPanel.svelte @@ -1292,6 +1292,16 @@ display: none; } + /* The repo's panel scrolls under the home indicator: the inset moves + from the panel's padding to its scroller's, as the sidebar's. */ + .main-panel { + padding-bottom: 0; + } + + .main-panel-scroll { + padding-bottom: calc(14px + env(safe-area-inset-bottom)); + } + .panel-body:not(.detail-open) .context-item.selected { background: transparent; } diff --git a/apps/staged/src/lib/features/settings/DoctorSettingsPanel.svelte b/apps/staged/src/lib/features/settings/DoctorSettingsPanel.svelte index 438651233..e5a446b67 100644 --- a/apps/staged/src/lib/features/settings/DoctorSettingsPanel.svelte +++ b/apps/staged/src/lib/features/settings/DoctorSettingsPanel.svelte @@ -219,6 +219,8 @@ min-height: 0; overflow-y: auto; padding: 14px; + /* The phone layout's bottom inset (SettingsPage's `.panel-pad`). */ + padding-bottom: calc(14px + var(--settings-panel-inset-bottom, 0px)); display: flex; flex-direction: column; gap: 12px; @@ -289,6 +291,14 @@ flex-shrink: 0; } + /* Finger-sized Copy details / Re-run on a touch screen. */ + @media (pointer: coarse) { + .header-actions :global([data-slot='button']) { + min-height: 36px; + padding-inline: 10px; + } + } + @media (max-width: 920px) { .panel-intro { flex-direction: column; diff --git a/apps/staged/src/lib/features/settings/GeneralSettingsPanel.svelte b/apps/staged/src/lib/features/settings/GeneralSettingsPanel.svelte index 6182544b2..8fb6cc28d 100644 --- a/apps/staged/src/lib/features/settings/GeneralSettingsPanel.svelte +++ b/apps/staged/src/lib/features/settings/GeneralSettingsPanel.svelte @@ -253,6 +253,8 @@ min-height: 0; overflow-y: auto; padding: 16px; + /* The phone layout's bottom inset (SettingsPage's `.panel-pad`). */ + padding-bottom: calc(16px + var(--settings-panel-inset-bottom, 0px)); display: flex; flex-direction: column; gap: 24px; diff --git a/apps/staged/src/lib/features/settings/KeyboardSettingsPanel.svelte b/apps/staged/src/lib/features/settings/KeyboardSettingsPanel.svelte index e01803041..251bcd4e0 100644 --- a/apps/staged/src/lib/features/settings/KeyboardSettingsPanel.svelte +++ b/apps/staged/src/lib/features/settings/KeyboardSettingsPanel.svelte @@ -445,6 +445,8 @@ min-height: 0; overflow-y: auto; padding: 14px; + /* The phone layout's bottom inset (SettingsPage's `.panel-pad`). */ + padding-bottom: calc(14px + var(--settings-panel-inset-bottom, 0px)); display: flex; flex-direction: column; gap: 12px; diff --git a/apps/staged/src/lib/features/settings/ProjectStatusOptionsSetting.svelte b/apps/staged/src/lib/features/settings/ProjectStatusOptionsSetting.svelte index c45583626..349e2b809 100644 --- a/apps/staged/src/lib/features/settings/ProjectStatusOptionsSetting.svelte +++ b/apps/staged/src/lib/features/settings/ProjectStatusOptionsSetting.svelte @@ -254,6 +254,13 @@ flex-wrap: wrap; } + /* The name field keeps a readable width and the swatches wrap under it + rather than squeezing it to a few letters beside them (seven 30px + swatches left it about 48px on a 402px phone). */ + .status-option-row > :global(input) { + flex-basis: 160px; + } + .swatches { gap: 4px; } diff --git a/apps/staged/src/lib/features/settings/SettingsPage.svelte b/apps/staged/src/lib/features/settings/SettingsPage.svelte index c91794241..00f943efe 100644 --- a/apps/staged/src/lib/features/settings/SettingsPage.svelte +++ b/apps/staged/src/lib/features/settings/SettingsPage.svelte @@ -234,11 +234,16 @@ } /* The panels are cards on the page's chrome; the bottom inset keeps them - clear of the home indicator (App.svelte's main leaves it to the panes). */ + clear of the home indicator (App.svelte's main leaves it to the panes). + On a phone (below) the card is dropped and the inset moves into the + panel body's padding through `--settings-panel-inset-bottom`, so the + body scrolls under the home indicator instead of stopping at a band of + chrome above it. */ .panel-pad { padding: 14px; padding-bottom: calc(14px + env(safe-area-inset-bottom)); overflow: hidden; + --settings-panel-inset-bottom: 0px; } @media (max-width: 920px) { @@ -277,5 +282,24 @@ .nav-meta { display: none; } + + /* Full-bleed panel: the nav row above is the only chrome, the panel + runs to the screen's edges and its body takes the bottom inset. */ + .panel-pad { + padding: 0; + --settings-panel-inset-bottom: env(safe-area-inset-bottom); + } + + .panel-pad > :global(*) { + border: 0; + border-radius: 0; + } + } + + /* A finger-sized tab row: the tabs are 32px tall at their padding. */ + @media (max-width: 920px) and (pointer: coarse) { + .nav-item { + min-height: 44px; + } } From 01f918805321ceeaa1366c926d840a3911057ad6 Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Thu, 12 Nov 2026 11:21:22 +1100 Subject: [PATCH 2/2] fix(staged): make the phone Settings card removal win on specificity, not bundle order In the phone layout SettingsPage drops each panel's card with `.panel-pad > :global(*) { border: 0; border-radius: 0 }`. Scoped, that selector has specificity (0,2,0). Each panel's root sets its own border and radius with a rule of the same weight, for example `.general-settings-panel.svelte-x`, so the two tie and the cascade falls back to source order. The override only won because the child components' CSS happens to be emitted before SettingsPage's in the bundle. Anything that changes that order, such as lazy-loading a panel so its styles load later, would bring the card's border and radius back on a phone. Qualify the selector with its `.settings-body` ancestor, `.settings-body .panel-pad > :global(*)`, so it outranks every panel's root rule on specificity and no longer depends on emission order. The rendered result is unchanged today. A comment above the rule records why the extra ancestor is there. Signed-off-by: Matt Toohey Co-Authored-By: Claude Fable 5.2 --- apps/staged/src/lib/features/settings/SettingsPage.svelte | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/staged/src/lib/features/settings/SettingsPage.svelte b/apps/staged/src/lib/features/settings/SettingsPage.svelte index 00f943efe..4ef083aae 100644 --- a/apps/staged/src/lib/features/settings/SettingsPage.svelte +++ b/apps/staged/src/lib/features/settings/SettingsPage.svelte @@ -290,7 +290,12 @@ --settings-panel-inset-bottom: env(safe-area-inset-bottom); } - .panel-pad > :global(*) { + /* Each panel's root sets its own border and radius at (0,2,0) specificity + (`.general-settings-panel.svelte-x`), the same as a bare + `.panel-pad > :global(*)` here. That tie is decided by bundle order, + which only happens to favour this file; the extra ancestor makes this + rule win on specificity so lazy-loading a panel cannot regress it. */ + .settings-body .panel-pad > :global(*) { border: 0; border-radius: 0; }