fix(ui): mobile layout for the inbox, note, search and browse pages

The health pass only covered the page it was looking at. The rest had the same
class of problem:

- Card headings put a title and its pills in one inline run, and `.pill` was
  `white-space: nowrap`. An inbox item labelled `Revision of "<title>"` carries a
  whole note title inside that pill, so it pushed the card — and the page —
  sideways on a phone. Those headings are now flex containers that wrap, and a
  pill may break its own text at the small breakpoint.
- The reject form pairs a reason input with a button. Inside a flex `.actions`
  the input collapsed toward its intrinsic size; it now takes the slack.
- The search filter row is eight controls. Stacked full width it was eight rows
  tall before a single result; it now lays out in two columns with the query and
  the submit button spanning.
- `white-space: nowrap` on table cells (added so the scroll container would do
  its job) made the browse table absurdly wide, since note titles are long and
  every one of them claimed a full line. Title, tags and the call-log ids now
  wrap within a bounded column; the short columns stay nowrap.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0139vHnNpS2sLNELjrAHX5Cu
This commit is contained in:
MarkusandClaude Opus 5 committed 2026-09-13 14:42:18 +00:00
1 parent 527799cbc9
commit 79f88fdd51
3 files changed
+22 -11

No files matched your search

+17 -6
View File
@@ -195,6 +195,8 @@ h1 small {
transition: box-shadow 0.15s ease, border-color 0.15s ease;
}
.card:hover { box-shadow: var(--shadow); border-color: var(--line-strong); }
.card h2, .card > h1 { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; }
.card h2 .pill, .card > h1 .pill { margin-left: 0; max-width: 100%; }
.card h2 a { color: inherit; text-decoration: none; }
.card h2 a:hover { color: var(--accent); }
@@ -322,6 +324,8 @@ form { display: inline; }
border-top: 1px solid var(--line);
}
.actions.bare { margin-top: 0; padding-top: 0; border-top: none; }
.actions form { display: inline-flex; gap: 0.4rem; align-items: center; }
.actions form input[type="text"] { flex: 1 1 10rem; min-width: 0; }
.actions details { width: 100%; margin-top: 0.3rem; }
.actions details summary { cursor: pointer; font-size: 0.86rem; padding: 0.2rem 0; }
.actions details[open] summary { margin-bottom: 0.5rem; }
@@ -395,7 +399,7 @@ form { display: inline; }
.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
th, td { text-align: left; padding: 0.5rem 0.75rem; border-bottom: 1px solid var(--line); white-space: nowrap; }
td.wrap, th.wrap { white-space: normal; min-width: 12rem; }
td.wrap, th.wrap { white-space: normal; min-width: 11rem; max-width: 26rem; }
thead th {
position: sticky;
top: 0;
@@ -472,11 +476,18 @@ pre.diff .hunk { color: var(--muted); font-weight: 600; }
/* full-width controls beat a ragged two-and-a-half-button row */
.actions form { display: flex; width: 100%; }
.actions > form > button, .actions > .button { width: 100%; justify-content: center; }
.filters { padding: 0.6rem; }
.filters input, .filters select, .filters button { width: 100%; }
.filters input[type="search"] { flex: 1 1 100%; }
.filters label { width: 100%; }
.actions > form > button, .actions > .button { flex: 1 1 auto; justify-content: center; }
.actions form input[type="text"] { flex: 1 1 6rem; }
/* a long note title in a pill must wrap rather than widen the card */
.pill { white-space: normal; }
/* the search filter row is eight controls: two columns halve its height,
with the query and the submit button spanning the full width */
.filters { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; padding: 0.6rem; }
.filters > * { width: 100%; min-width: 0; }
.filters input[type="search"], .filters button, .filters label { grid-column: 1 / -1; }
.history-compare { width: 100%; }
.history-compare label, .history-compare select { flex: 1 1 100%; }
}
+3 -3
View File
@@ -16,7 +16,7 @@
<div class="table-wrap">
<table>
<thead><tr>
<th><a href="/ui/browse?order=title&state={{ state }}&tag={{ tag }}">Title</a></th>
<th class="wrap"><a href="/ui/browse?order=title&state={{ state }}&tag={{ tag }}">Title</a></th>
<th><a href="/ui/browse?order=type&state={{ state }}&tag={{ tag }}">Type</a></th>
<th><a href="/ui/browse?order=state&state={{ state }}&tag={{ tag }}">State</a></th>
<th><a href="/ui/browse?order=tags&state={{ state }}&tag={{ tag }}">Tags</a></th>
@@ -25,10 +25,10 @@
<tbody>
{% for r in rows %}
<tr class="{{ 'superseded' if r.superseded_by else '' }}">
<td><a href="/ui/n/{{ r.id }}">{{ r.title }}</a>{% if r.revises %} <span class="pill warn">Revision</span>{% endif %}</td>
<td class="wrap"><a href="/ui/n/{{ r.id }}">{{ r.title }}</a>{% if r.revises %} <span class="pill warn">Revision</span>{% endif %}</td>
<td>{{ r.type }}</td>
<td>{{ r.state }}</td>
<td>{% for t in r.tags %}<span class="tag">#{{ t }}</span>{% endfor %}</td>
<td class="wrap">{% for t in r.tags %}<span class="tag">#{{ t }}</span>{% endfor %}</td>
<td>{{ r.updated }}</td>
</tr>
{% else %}
+2 -2
View File
@@ -66,11 +66,11 @@
<h3>Recent MCP calls</h3>
<div class="table-wrap">
<table>
<thead><tr><th>Time</th><th>Tool</th><th>Source</th><th>ok</th><th>ms</th><th>ids</th></tr></thead>
<thead><tr><th>Time</th><th>Tool</th><th>Source</th><th>ok</th><th>ms</th><th class="wrap">ids</th></tr></thead>
<tbody>
{% for c in calls %}
<tr><td>{{ c.ts }}</td><td>{{ c.tool }}</td><td>{{ c.get('source', '') }}</td><td>{{ c.get('ok', '') }}</td><td>{{ c.get('ms', '') }}</td>
<td>{% for i in c.get('ids', []) %}<a href="/ui/n/{{ i }}">{{ i[:8] }}</a> {% endfor %}</td></tr>
<td class="wrap">{% for i in c.get('ids', []) %}<a href="/ui/n/{{ i }}">{{ i[:8] }}</a> {% endfor %}</td></tr>
{% else %}<tr><td colspan="6" class="empty">none</td></tr>{% endfor %}
</tbody>
</table>