# Mobile-compatible Block UI

Build one standard or custom Block interface that stays usable in 320-pixel phone viewports through desktop.

# Mobile-compatible Block UI

Build one Block contract for every size. Inputs, outputs, state, actions,
permissions, and runtime do not change when the interface becomes compact.
StillMade reorganizes standard controls automatically and keeps custom views in
the existing opaque sandbox.

## Standard UI

Prefer `manifest.ui` and `manifest.uiLayout`. The host owns field sizing, focus,
touch targets, stacked preview/results, tab overflow, safe-area spacing, and
software-keyboard behavior. Use `uiLayout` only to group complete inputs and
outputs; do not create a second mobile manifest or split an editor into tiny
Blocks.

Tabs and sections must retain every essential input and output. A compact layout
may put secondary tools behind a labelled section or sheet, but the primary
action and focused field must remain reachable. Resizing the preview does not run
the Block and must not reset its values, selection, state, progress, or result.

## Custom UI

Custom HTML, CSS, and JavaScript continue to use `view` and `StillMade.run`.
Design from the view container rather than a device name:

```css
.workspace { container: block-workspace / inline-size; min-width: 0; }
.layout { display: grid; grid-template-columns: minmax(0, 2fr) minmax(240px, 1fr); }
@container block-workspace (max-width: 600px) {
  .layout { grid-template-columns: minmax(0, 1fr); }
}
```

The sandbox supplies viewport-fit, safe-area padding, readable form defaults,
44-pixel ordinary controls, media containment, and focus styling. Authored CSS
still owns specialized workspace layout. A 320 CSS-pixel phone viewport leaves
less than 320 pixels inside the host's preview gutters. Size from the embedded
view's actual container, avoid a 320-pixel minimum width, wrap long labels, and
isolate intentional canvas/timeline panning from
the surrounding toolbar. Provide visible buttons or menus for actions otherwise
available by hover, drag, right-click, or keyboard shortcut. Label fields and
announce loading, errors, and completed output with `role="status"`,
`role="alert"`, or `aria-live` as appropriate. For deterministic custom-view
checks, set `data-stillmade-state="loading"`, `"error"`, or `"success"` on the
visible result area as each state occurs. The browser profile runs the local
success fixture, then injects a local executor failure to exercise the same
view's error path without calling a provider. Standard controls receive the
same failure and must show their error result. A permanently mounted live region
does not demonstrate that an error was actually shown. If the test never
reaches a state, phone support remains unverified rather than inferred.

The maintained `examples/custom-interface.stillmade.json` demonstrates one
custom workspace whose settings and result stack from the same state and action
contract.

For deterministic browser checks, mark a custom form control with
`data-stillmade-input="portName"` so the phone profile can enter the package's
test fixture through the real UI before pressing its run action. This marker
does not change the Block's input contract or grant access to host services.
For a text-bearing object fixture such as `{brief:{text:"…"}}`, the profile
enters its `text` into the marked text field. Mark the primary button with
`data-stillmade-action="run"` when the view has more than one button.
The existing `data-stillmade-share` marker is also recognized for shared text
fields. A custom view without a reachable mapped control must not be counted
as having passed its fixture's success interaction.

## Preview and authoritative validation

The Create preview includes Compact (320), Phone (390), Tablet (768), phone
landscape (844 × 390), and Desktop (1280) container presets. Changing a preset
only changes available space. Its quick check helps find immediate host overflow
and small touch targets; imported and published packages still run the
authoritative profile in the real Block/Project Type host.

The SDK `testPlatforms` gate records the exact package digest plus SDK, renderer,
and check versions. A trusted browser adapter covers Light, Dark, and White at
320, 390, 768, 1280, and phone landscape. It checks the main touch task, empty,
populated, loading, error, success, long-label and enlarged-text states, and
continuity through resize/rotation and panel toggles. Custom views must visibly
enter each claimed state during the check; source markup alone is not evidence
of a working error path. Fixture execution is local
or mocked; the mobile UI profile never authorizes a provider call or spends
credits.

Reports supplied inside a package are ignored. A changed package or changed
renderer/check version needs a new report. Failures name the affected view,
control, and CSS size and remain repairable in draft preview. Passing the profile
does not make an unavailable desktop binary, local GPU, provider, or credential
available on a phone; runtime capability checks remain separate.

For a local preview build, `node scripts/platform-tests/run.mjs --engine=chromium --require-complete` uses that same trusted embedded profile
and saves per-size captures and a digest-bound report. Firefox and WebKit runs
are exploratory layout checks; they cannot supply the profile's state and
continuity evidence. A report from any local command does not grant a
Marketplace support claim or replace StillMade's server-owned import review.

Before public release, StillMade also smoke-tests representative shared UI in
real iOS Safari and Android Chrome. Gesture-heavy custom editors require a
focused real-device check. Those operational checks complement the deterministic
gate; they are not inferred from an author claim.
