simocracy-v2 · modal-cutoff-audit

Modal overflow + cutoff audit

@daviddao

Prompted by a user-reported cutoff on the Create New Sim dialog, I walked agent-browser through every reachable modal on prod at a realistic 13-inch viewport (1280×577) and measured child-element overflow against the dialog bounding box with a DOM probe. Three real clipping bugs, two structural risks, the rest pass.

Date: 2026-04-22 · Target: simocracy.org · Viewport: 1280×577 · partial


Headline result

19
Modals audited
3
Confirmed cutoffs
2
Structural risks
14
Clean

Headline. The reported Create New Sim cutoff reproduces — the right-hand column (name field, reset row, save button) overflows DialogContent by 79 px. Two other modals fail the same test: Connect to Agent overflows both the top and bottom of the viewport with no internal scroll, and the FTC S-Process run view's tab strip clips 🔍 Disagreement at the right edge. Two additional surfaces pass the automated probe but have layout risks worth flagging — the FTC proposal-detail modal lets a 16:10 hero image eat 85% of dialog height, and two smaller DialogContents ship with neither max-h-[90vh] nor overflow-y-auto, so they'd clip silently on shorter viewports.

Methodology

Signed in once as satyam2.climateai.org, then walked each surface that opens a modal: /my-sims (create/edit sim, delete), sim profile (chat, interview, connect to agent, edit constitution, edit style), /events (create event, author template, allocation picker), /senate (building sidebar, submit proposal, start discussion), /ftc-sf (floor sidebar, submit proposal, proposal detail, S-Process). For each open dialog I ran a DOM probe that captured the dialog's bounding rect and walked every descendant's getBoundingClientRect(), flagging anything whose right edge extended >4 px beyond the dialog's right edge — i.e. the actual definition of a cut-off button — and separately logging dialogs whose content extended below the viewport with no internal scrollbar.

Findings — confirmed cutoffs

Blocker — Create New Sim dialog overflows by 79 px

Opening + Create New Sim from /my-sims renders a two-column layout where the right column (Sim Name input, the ↩ Reset / 🔄 Reset Colors / 🎲 Randomize button row, and the Save to ATProto button) spills 79 px past the dialog's right edge. The Randomize pill is visibly truncated to “RAN…” and Save to ATProto's right edge hits the dialog border.

Root cause: components/avatar/avatar-editor.tsx — the right column uses flex-col gap-3 flex-1 w-full without min-w-0, and the reset-button row flex gap-2 has three pills at fixed intrinsic width with no wrapping. The outer grid uses the avatar preview at intrinsic size and lets the right column absorb the remainder, which becomes negative when the viewport is 1280 px.

Probe output:

overflowers = [
  { tag: 'div',    txt: 'Sim Name0/64 characters↩ Reset…',  overR: 79, cls: 'flex flex-col gap-3 flex-1 w-full' },
  { tag: 'input',  txt: '',                                  overR: 79 },
  { tag: 'div',    txt: '↩ Reset🔄 Reset Colors🎲 Randomize', overR: 79, cls: 'flex gap-2' },
  { tag: 'button', txt: '🎲 Randomize',                       overR: 79, cls: 'whitespace-nowrap…' },
  { tag: 'button', txt: 'Save to ATProto',                    overR: 79 }
]

Fix candidates (non-prescriptive):

Blocker — Connect to Agent dialog overflows viewport top & bottom

Opening Connect to Agent from a sim profile produces a dialog that is 601 px tall in a 577 px viewport, with no internal scroll. Its top is rendered at y = -12 (header clipped) and bottom at y = 589 (“Full heartbeat routine” link clipped). The dialog title and the sign-in steps are both partially off-screen on this viewport.

Root cause: components/sim/sim-profile.tsx:506 ships <DialogContent className="max-w-lg"> with no height cap and no scroll container. The content is three numbered steps plus two code blocks; perfectly reasonable, but cumulatively taller than a short laptop viewport.

Fix candidate: match the convention used by most other modals — className="max-w-lg max-h-[90vh] overflow-y-auto".

Blocker — FTC S-Process run view: 🔍 Disagreement tab clipped by 22 px

Inside the FTC S-Process modal, opening a past run renders a horizontal tab strip with one tab per recommender sim plus Results and 🔍 Disagreement. On a 1280 px viewport the tab strip doesn't wrap, doesn't scroll, and the rightmost 🔍 Disagreement pill overflows by 22 px, rendering as “🔍 Disagreeme”. With more recommenders the overflow will grow.

Fix candidates: add overflow-x-auto with custom scrollbar styling to the tab strip, let the tab row flex-wrap, or stash overflowing tabs behind a More… popover.

Findings — structural risks

Warning — FTC proposal-detail hero image eats 85% of dialog height

The FTC floor proposal-detail modal (components/ftc-sf/proposal-detail-modal.tsx) renders a max-h-[85vh] glass panel whose first child is a aspect-[16/10] hero image. On a 577 px viewport: panel height 490 px, hero height 419 px. The proposal title is almost entirely below the fold on first open — the user sees a big gray placeholder and an X button and has to scroll to discover what they clicked. The gathering proposal-detail modal in gathering-world.tsx:945 uses the same pattern and has the same issue.

Fix candidates: cap the hero at max-h-[30vh] or max-h-[200px], use aspect-[21/9], or swap the order so the title sits above a smaller banner strip.

Warning — two DialogContents lack both max-h cap and overflow scroll

Static grep of the codebase found two DialogContents that ship with neither a height cap nor overflow-y-auto, meaning any future content growth will clip silently on short viewports:

Fix candidate: apply the house standard — max-h-[90vh] overflow-y-auto — to both.

Walkthrough — the clipped ones

01Create New Sim — Randomize pill clipped, Save to ATProto button flush to the right edge.
08Connect to Agent — title pressed to the top edge, bottom link row below the viewport fold.
19FTC S-Process run — the last tab reads “🔍 Disagreeme”. 22 px of overflow.
17FTC proposal detail on first open — hero eats 85% of the dialog, title only peeks in at the bottom edge.
17bSame modal after scrolling 400 px. The content is there, but discoverability is poor.
19bS-Process run body scrolled — note MVF value-curve chart sized at ~320 px inside an 896 px dialog. Lots of unused horizontal space.

Walkthrough — the clean ones

02Edit Constitution — max-h-[90vh] overflow-y-auto. Probe: 0 overflowers.
03Edit Speaking Style — fits well under the viewport cap.
04Chat with Nyariko — max-h-[80vh] flex column.
05Interview Mode — intro screen.
06Interview — template picker.
07Interview — question 1 of 28.
09Create an Event — top. max-h-[90vh] overflow-y-auto does its job; internal scroll container is 1723 px inside a 517 px dialog.
10Create an Event — scrolled to the Create Event CTA. Clean.
11Author a new template — nested dialog, clean.
12Select Allocation Mechanism — portal picker. Fine at rest; minor layering issue where the outer dialog's Create Event button bleeds through as a dark bar beneath the picker.
15Senate Submit Proposal — top.
15bSenate Submit Proposal — bottom. Internal scroll.
18FTC S-Process — landing screen (past runs list). Clean.
20FTC Submit Proposal — fits, but 1 px from the viewport bottom. No slack, no scroll. Structural risk.
24Start Discussion — opponent picker. Clean.
27Delete Sim — small AlertDialog. Clean.

Coverage — the inventory

ModalFileDialogContent classStatus
Create New Sim / Edit Appearancecomponents/sim/appearance-editor-dialog.tsxsm:max-w-3xl max-h-[90vh] overflow-y-autoclipped
Edit Constitutioncomponents/sim/agents-editor-dialog.tsxsm:max-w-2xl max-h-[90vh] overflow-y-autopass
Edit Speaking Stylecomponents/sim/style-editor-dialog.tsxsm:max-w-2xl max-h-[90vh] overflow-y-autopass
Chat with …components/sim/sim-chat-modal.tsxsm:max-w-lg max-h-[80vh] flex flex-col …pass
Interview Modecomponents/sim/interview-modal.tsxsm:max-w-lg p-0 gap-0 overflow-hiddenpass
Connect to Agentcomponents/sim/sim-profile.tsxmax-w-lgclipped
Create Evaluationcomponents/sim/hypercerts-panel.tsxsm:max-w-mdrisk
Start Discussioncomponents/sim/sim-discussion-modal.tsxsm:max-w-2xl max-h-[85vh] flex flex-col …pass
Create / Edit Eventcomponents/events/gathering-form-dialog.tsxmax-w-lg max-h-[90vh] overflow-y-autopass
Author a new templatecomponents/events/template-author-dialog.tsxmax-w-lg max-h-[85vh] overflow-y-autopass
Submit Proposal (Senate)components/events/gathering-proposal-form.tsxmax-w-lg max-h-[90vh] overflow-y-autopass
Proposal detail (gathering)components/events/gathering-world.tsx:945 (portal)max-w-2xl max-h-[85vh] overflow-y-auto + 16:10 herohero 85%
Select Allocation Mechanismcomponents/events/gathering-form-dialog.tsx (portal)pass
FTC Submit Proposalcomponents/ftc-sf/proposal-form-dialog.tsxsm:max-w-xlrisk
FTC Proposal detailcomponents/ftc-sf/proposal-detail-modal.tsx (portal)max-w-2xl max-h-[85vh] overflow-y-auto + 16:10 herohero 85%
FTC S-Processcomponents/ftc-sf/ftc-s-process-modal.tsxsm:max-w-4xl max-h-[85vh] flex flex-col …tab clipped
Generic S-Processcomponents/s-process/s-process-modal.tsxsm:max-w-4xl max-h-[85vh] flex flex-col …same shared tab pattern
MVF Detailcomponents/s-process/mvf-detail-modal.tsxsm:max-w-2xl max-h-[90vh] overflow-y-autonot triggered
Past Hearing / Senate Hearingcomponents/senate/…-modal.tsxsm:max-w-2xl max-h-[85vh] flex flex-col …not triggered
Floor Lead Editorcomponents/ftc-sf/floor-lead-editor.tsxsm:max-w-mdfacilitator-only
Delete Simcomponents/my-sims/sim-character-card.tsx (AlertDialog)defaultpass
Sign-in popovercomponents/navbar.tsxRadix popoverpass

Reproducing

Targethttps://www.simocracy.org Test handlesatyam2.climateai.org · DID did:plc:cpoagodpqrgs4t7thi5z37uf · PDS climateai.org Viewport1280×577 (13-inch MacBook-ish laptop) Date2026-04-22 Toolingagent-browser open <url>agent-browser eval <probe.js>agent-browser screenshot. ProbeFor each [role=dialog], walk querySelectorAll('*') and flag any descendant whose getBoundingClientRect().right exceeds the dialog's right by >4 px; also log dialog bottom edge vs innerHeight and whether scrollHeight > clientHeight. Screenshotsassets/01–27-*.png

Net recommendation for eng. Three quick fixes unblock most of this: (1) add min-w-0 and let the reset-button row wrap in avatar-editor.tsx; (2) apply the house-standard max-h-[90vh] overflow-y-auto to the three outliers (sim-profile.tsx:506, hypercerts-panel.tsx:116, proposal-form-dialog.tsx:221); (3) make the FTC S-Process tab strip scroll horizontally or wrap. The hero-image-too-tall finding on proposal-detail modals is cosmetic but noticeable enough on a 13-inch laptop that I'd cap the hero at ~200 px and put the title above the fold.