+ {/* The ref is on the figure rather than the panel: in the two-column
+ layout the SVG's width is its *column's* width, and measuring the
+ panel would size the mouth for space the console is occupying. */}
+
+
+ {/* The mouth. Three ellipses of the one hue at descending wash weight —
a throat seen edge-on, not a second series. */}
-
-
-
-
-
- {/* The notes already inside, turning slowly. Drawn before the marks in
- flight so an arriving note passes in front of the population it is
- about to join. */}
- {stock?.shells.map((shell, si) => (
-
-
- {shell.marks.map((m, mi) => (
-
- ))}
-
-
- ))}
-
- {particles.current.map((_, i) => (
- {
- pool.current[i] = node
- }}
+
+
- ))}
-
+
+
-
- {last === null ? (
-
Watching for the next block.
- ) : (
- <>
-
#{last.height.toLocaleString('en-US')}
-
- {last.notesIn.toLocaleString('en-US')} in
- {last.notesIn > 0 && ` · ${tokens(last.amountIn, decimals, 1)} ${symbol}`}
-
-
- {last.notesOut.toLocaleString('en-US')} out
- {last.notesOut > 0 && ` · ${tokens(last.amountOut, decimals, 1)} ${symbol}`}
-
- >
- )}
- {/* Outside the block branch on purpose: the held population is drawn
+ {/* The notes already inside, turning slowly. Drawn before the marks in
+ flight so an arriving note passes in front of the population it is
+ about to join. */}
+ {stock?.shells.map((shell, si) => (
+
+
+ {shell.marks.map((m, mi) => (
+
+ ))}
+
+
+ ))}
+
+ {particles.current.map((_, i) => (
+
{
+ pool.current[i] = node
+ }}
+ cx={cx}
+ cy={cy}
+ r={2}
+ opacity={0}
+ />
+ ))}
+
+
+
+ {last === null ? (
+ Watching for the next block.
+ ) : (
+ <>
+ #{last.height.toLocaleString('en-US')}
+
+ {last.notesIn.toLocaleString('en-US')} in
+ {last.notesIn > 0 && ` · ${tokens(last.amountIn, decimals, 1)} ${symbol}`}
+
+
+ {last.notesOut.toLocaleString('en-US')} out
+ {last.notesOut > 0 && ` · ${tokens(last.amountOut, decimals, 1)} ${symbol}`}
+
+ >
+ )}
+ {/* Outside the block branch on purpose: the held population is drawn
from the moment the page loads, and a reader arriving between blocks
would otherwise see forty-five turning marks with nothing saying
what they are. */}
- {stock !== null && outstanding !== null && (
-
- {outstanding.toLocaleString('en-US')} notes held
- {stock.per > 1 && ` · one mark per ${stock.per.toLocaleString('en-US')}`}
-
- )}
- {reduced && motion off }
+ {stock !== null && outstanding !== null && (
+
+ {outstanding.toLocaleString('en-US')} notes held
+ {stock.per > 1 && ` · one mark per ${stock.per.toLocaleString('en-US')}`}
+
+ )}
+ {reduced && motion off }
+
{/* What the marks were. The stage on its own is a dot travelling inward,
@@ -554,7 +587,7 @@ export function WormholeStage({
return (
- {repeat ? '' : `#${line.height.toLocaleString('en-US')}`}
+ {repeat ? '' : }
{kind.glyph} {kind.label}
@@ -562,10 +595,19 @@ export function WormholeStage({
{tokens(line.amount, decimals, 4)} {symbol}
- {shortAddress(line.to)}
+
+ {chain === null ? (
+ shortAddress(line.to)
+ ) : (
+
+ {shortAddress(line.to)}
+
+ )}
+
{line.elided > 0 && (
-
- +{line.elided.toLocaleString('en-US')} more in this block
+
+ +{line.elided.toLocaleString('en-US')} more in{' '}
+
)}
diff --git a/web/src/index.css b/web/src/index.css
index fa29016..2837c41 100644
--- a/web/src/index.css
+++ b/web/src/index.css
@@ -1048,6 +1048,36 @@ tr.mine .share-bar > i {
padding: 6px 0 2px;
}
+/* Side by side once there is room for both.
+ *
+ * Stacked, the console pushes the panel past a phone screen's height and the
+ * mouth and the lines describing it cannot be read at the same time — which is
+ * the entire point of having both. The breakpoint is where the console still
+ * fits its widest line (a height, a kind, an amount and an address) without
+ * wrapping; below it they stack, and the figure takes the full width back. */
+@media (min-width: 1100px) {
+ .stage-wrap {
+ display: grid;
+ /* 400px is not a taste: it is what one line needs — the height, kind and
+ amount columns plus a shortened address and three gaps come to ~354px,
+ and the column's own padding takes the rest. Measured at 360px every
+ line wrapped to two, which is worse than stacking. The breakpoint is
+ where that column can exist without starving the figure. */
+ grid-template-columns: minmax(0, 1fr) clamp(400px, 36%, 470px);
+ padding: 6px 0 0;
+ }
+
+ .stage-log {
+ border-left: var(--rule);
+ /* Stretched to the figure's height so the panel has a straight bottom edge
+ whatever the console is holding. Scrolls rather than growing: the buffer
+ is fixed, but a wrapped line must not lengthen the panel. */
+ height: 100%;
+ overflow-y: auto;
+ padding-top: 10px;
+ }
+}
+
.stage {
display: block;
}
@@ -1181,19 +1211,21 @@ tr.mine .share-bar > i {
.stage-log-height {
color: var(--text-muted);
- min-width: 66px;
+ min-width: 62px;
}
/* Direction repeats what the mark did, in a glyph, so a line and its dot can be
matched without reading the label. Same reasoning as the flow chart: the
encoding is geometry, never a second hue — every kind wears the one colour. */
.stage-log-kind {
- min-width: 72px;
+ min-width: 66px;
color: var(--data-bright);
}
.stage-log-amount {
- min-width: 132px;
+ /* Sized to the widest real amount rather than generously: the column has to
+ survive being squeezed into the console's own column at 1000px. */
+ min-width: 104px;
color: var(--text-primary);
}
@@ -1201,6 +1233,33 @@ tr.mine .share-bar > i {
color: var(--text-muted);
}
+/* Console links: the block a note landed in, and the account it credited.
+ *
+ * Underlined on hover rather than tinted, following `a.ticker-height`: the
+ * columns already carry meaning through colour — muted for the height and the
+ * address, bright for the kind — and recolouring a link on hover would make it
+ * momentarily read as a different column. The dotted rule is the affordance;
+ * it costs no colour at all. */
+.stage-log a {
+ text-decoration: underline;
+ text-decoration-style: dotted;
+ text-underline-offset: 3px;
+ text-decoration-color: var(--border-strong);
+}
+
+.stage-log a:hover {
+ color: var(--data-bright);
+ text-decoration-color: var(--data-bright);
+}
+
+/* The count of what is not shown. It fits on the line in the wide layout and
+ wraps in the narrow column, so it carries the height column's indent either
+ way — wrapped and flush left it reads as a new record rather than as a note
+ about the one above it. */
+.stage-log-more {
+ padding-left: 62px;
+}
+
/* A meter: one ratio against its limit.
*
* The track is the same hue at wash weight rather than a neutral grey, so the