Skip to content

mac: the stage is a panel on the window ground - #299

Merged
stupart merged 1 commit into
mainfrom
feat/stage-panel
Sep 16, 2026
Merged

stupart merged 1 commit into
mainfrom
feat/stage-panel

Conversation

@stupart

@stupart stupart commented Sep 16, 2026

Copy link
Copy Markdown
Owner

§3: "the stage is a surface panel inset 8 from the window, radius 12 (ConchRadius.medium), with a 0.5 pt hairline shadow. No other cards." The lab's #stage gives it in values:

#stage{ top:8px; right:8px; bottom:8px; left:var(--sideW);
        background:var(--surface); border-radius:12px;
        box-shadow:var(--shPanel); overflow:hidden }
--shPanel: 0 0 0 .5px rgba(0,0,0,.08), 0 1px 3px rgba(0,0,0,.04);

The pane was flush with the window and divided from the sidebar by a 1 pt rule. Now it is a panel: inset 8 on all four sides so the ground shows through, surface, radius 12, a 0.5 hairline ring, and a very quiet drop. The sidebar's rule is gone — #stage has no left border, and the panel's own edge is the separation.

The drop comes from .conchElevation(.raised) (radius 1.5, y 1), not .floating (14, y 10). The composer floats; the stage merely sits. No ConchElevation case carries a ring, so it's drawn explicitly — the same way the composer does it, rather than inventing a token for one use.

Right shape, wrong fill

The first build had the panel's geometry and the window ground inside it — because the transcript, the pane body, the 52 pt header and every deliverable surface painted ConchPalette.bg over the panel's surface. In light that's #F2F1EF over #FFFFFF: a panel-shaped hole. I only caught it by photographing it.

So the sweep: ConversationStackView's scroll ground, ConversationPane's body, sessionBar, and all 13 ground references in ReviewView — which renders only inside the stage since #284 deleted the full-window overlay. That includes the cover which hides WKWebView's white flash: left as ground, it would itself be a visible rectangle against the panel.

Three ground fills remain, all outside the panel: the window, the title strip, and the ledger — which is what the panel sits on.

Guards

mutation result
the panel loses its inset and fills the window 1 fail
the panel takes the composer's float instead of the stage's quiet drop 1 fail
the surface fill goes back to the window ground 1 fail
the hairline ring is dropped 1 fail
the sidebar's 1 pt rule comes back beside the panel 1 fail
a ground fill creeps back inside the pane 1 fail
one deliverable surface reverts to the ground 1 fail
the transcript paints the ground over the panel 1 fail

The "nothing inside the pane paints the ground" invariant is asserted structurally, not as a count, so it survives a refactor that moves a fill around.

Gate

bun test 2304/0 exit 0 · tsc --noEmit exit 0 · Mac xcodebuild BUILD SUCCEEDED · iOS xcodebuild BUILD SUCCEEDED · photographed on the real window, twice — once to find the wrong fill, once to confirm it.

Not here

The lab has no 🐚 wordmark strip: §5 drops it, with traffic lights over the sidebar and the panel starting 8 from the window top. That's the header slice (breadcrumb, state text, terminal and details buttons) and it's next.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SfEX6bfwCGXtThk1JRNmsE

§3: the stage is a `surface` panel inset 8, radius 12, with a 0.5pt hairline
shadow -- "No other cards." The lab's #stage gives the values. The pane was
flush with the window and split from the sidebar by a 1pt rule; now the
ground shows through an 8pt inset on all four sides and the panel's own edge
is the separation, so that rule is gone.

The drop is .raised (radius 1.5, y 1), not .floating (14, y 10): the composer
floats, the stage sits. No ConchElevation case carries a ring, so it is drawn
explicitly, as the composer already does.

The first build had the right shape and the wrong fill -- the transcript, the
pane body, the 52pt header and every deliverable surface painted the window
ground over the panel's surface, which in light is #F2F1EF over #FFFFFF: a
panel-shaped hole. Caught by photographing it. Swept: ConversationStackView,
ConversationPane, sessionBar, and all 13 ground references in ReviewView,
which renders only inside the stage since #284 removed the full-window
overlay -- including the cover that hides WKWebView's white flash, which as
ground would be a visible rectangle against the panel.

Three ground fills remain, all outside: the window, the title strip, and the
ledger, which is what the panel sits on. The invariant is asserted
structurally rather than as a count.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfEX6bfwCGXtThk1JRNmsE
@stupart
stupart merged commit 18c7292 into main Sep 16, 2026
2 checks passed
@stupart
stupart deleted the feat/stage-panel branch September 16, 2026 20:53
stupart added a commit that referenced this pull request Sep 16, 2026
`--shRaised` IS defined in the lab — line 17, and line 20 for dark. The grep
behind the claim that it wasn't looked for the variable at the start of a line,
and the lab's `:root` is minified onto one. So #300 shipped the selected
segment flat AND added a guard asserting it stay that way. Both are corrected
here; the guard is inverted rather than deleted, so the mistake cannot return
quietly.

Reading the whole table turned up the second divergence, which #299 introduced:
the stage panel borrowed `.raised`, and `ElevationModifier` doubled every
shadow on dark. The lab's `--shPanel` keeps its ring and drops its shadow
outright on dark — something no blanket rule can express.

Each level now carries the lab's own pair, and `panel` becomes its own level:

                light            dark
    --shPanel   r1.5 y1  .04     ring only, no drop
    --shRaised  r1   y1  .14     r1   y1  .4
    --shFloat   r14  y10 .24     r14  y10 .7
    --shOver    r32  y24 .32     r32  y24 .75

CSS blur is twice SwiftUI's shadow radius. Two more were wrong on the way past:
`.overlay` sat at r24/y18/.26 against the lab's r32/y24/.32, and `.floating`
computed .44 on dark where the lab asks .7.

Elevation had no test coverage whatsoever. It has seven tests now, including a
pixel test of the modifier itself — every value test still passes with the
doubling rule in place, so the values alone could never catch its return.

The segment's hover fill is recorded as the app's own: the lab gives
`.seg button` no `:hover` rule at all.

Gated: bun test 2309/0, tsc clean, swift test 138/0, Mac and iOS both build
(CI builds neither). Twelve mutations across the tokens, the modifier and the
source guards; twelve killed.


Claude-Session: https://claude.ai/code/session_01SfEX6bfwCGXtThk1JRNmsE

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant