css: grid-only layout — convert every flex container to grid + pin column widths

Two fixes in one — the immediate layout bug from the screenshot (timeline
sliding into column 1 with controls eating ~80% of the viewport) and
the architectural rule that all zebra page layout uses grid.

Layout bug (was: when cameras-col gets .hidden + the global .hidden
utility's display:none !important, the grid auto-placement promoted
.timeline into column 1 and .controls into column 2 → controls took
the 1fr middle track). Fix:

- explicit grid-column: 1/2/3 on cameras-col / timeline / controls so
  each child stays in its assigned column regardless of siblings going
  display:none
- .cameras-col uses 'display: grid !important' to override the global
  .hidden util, then only its content (h2 + #cameras) goes display:none
  via separate selectors when the .hidden class is present
- controls track clamped to min(360px, 50vw) so a wide window can't
  let the side panel eat the screen-share area

Grid-only refactor:
- every flex container converted: .timeline, .cameras-col, .game-tabs,
  .screen-tile, .screen-meta, .tap-play, .camera-tile, .row,
  .mod-actions, .invite-banner, .invite-actions, .notice-banner
- chat.html + zebra-audio.html same treatment (.row, .field-row,
  .share-box .copy-row, the inline H2 style, .mode-toggle, .dot)
- inline 'style=flex:1' on inputs/meters in chat.html replaced with
  'style=width:100%'
- now zero 'display: flex' / 'inline-flex' across all five zebra pages
- CLAUDE.md documents the grid-only rule under web-page authoring
This commit is contained in:
Russell Ballestrini 2026-06-02 09:12:38 -04:00
parent 95851371bc
commit eed5348567
No known key found for this signature in database
4 changed files with 137 additions and 55 deletions

View file

@ -53,11 +53,16 @@
button:disabled { opacity: 0.3; cursor: default; }
button.invert { background: #000; color: #fff; }
button.invert:hover:not(:disabled) { background: #333; }
.row { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.75rem; flex-wrap: wrap; }
.row {
display: grid; grid-auto-flow: column;
grid-template-columns: max-content minmax(0, 1fr);
grid-auto-columns: max-content;
align-items: center; gap: 0.75rem; margin-bottom: 0.75rem;
}
.dot {
width: 9px; height: 9px; border-radius: 50%;
border: 1px solid #000; background: #fff;
flex-shrink: 0; transition: background 0.15s;
transition: background 0.15s;
}
.dot.on { background: #000; }
.dot.warn { background: #888; }
@ -71,8 +76,11 @@
}
input[type=text], input[type=password], select { width: 100%; }
textarea { width: 100%; resize: vertical; min-height: 4.5rem; }
.field-row { display: flex; gap: 0.5rem; margin-bottom: 0.5rem; }
.field-row > input, .field-row > textarea { flex: 1; }
.field-row {
display: grid; grid-template-columns: minmax(0, 1fr) max-content;
gap: 0.5rem; margin-bottom: 0.5rem;
}
.field-row > input, .field-row > textarea { width: 100%; min-width: 0; }
.key-display {
border: 1px solid #ccc; padding: 0.5rem;
font-family: monospace; font-size: 0.7rem;
@ -127,7 +135,8 @@
}
details[open] > summary { margin-bottom: 0.5rem; }
.mode-toggle {
display: inline-flex; border: 1px solid #000;
display: inline-grid; grid-auto-flow: column; grid-auto-columns: max-content;
border: 1px solid #000;
font-size: 0.78rem; user-select: none;
}
.mode-toggle > label {
@ -152,11 +161,14 @@
.share-box .qr-canvas {
width: 320px; height: 320px;
border: 1px solid #ccc; background: #fff;
display: flex; align-items: center; justify-content: center;
display: grid; place-items: center;
font-size: 0.65rem; color: #999;
}
.share-box input { width: 100%; font-size: 0.7rem; }
.share-box .copy-row { display: flex; gap: 0.4rem; margin-top: 0.3rem; }
.share-box .copy-row {
display: grid; grid-template-columns: minmax(0, 1fr) max-content;
gap: 0.4rem; margin-top: 0.3rem;
}
.share-box .copy-row button { font-size: 0.75rem; padding: 0.25rem 0.7rem; }
@media (max-width: 600px) {
.share-box { grid-template-columns: 1fr; }
@ -250,7 +262,7 @@ try {
<h2>identity</h2>
<div class="row">
<label for="handle-in">handle:</label>
<input type="text" id="handle-in" style="flex:1; min-width:0" placeholder="your handle">
<input type="text" id="handle-in" style="width:100%; min-width:0" placeholder="your handle">
<span class="status-line" id="id-status"></span>
</div>
<div class="row" style="margin-top:0.5rem">
@ -269,7 +281,7 @@ try {
<h2>room (passphrase mode)</h2>
<div class="row">
<input type="password" id="passphrase-in" placeholder="room passphrase — everyone in the room types the same one"
style="flex:1; min-width:0">
style="width:100%; min-width:0">
</div>
<div class="row">
<button id="btn-pp-join" class="invert">enter room</button>
@ -307,12 +319,12 @@ try {
</div>
<div class="row" style="margin-top:0.4rem">
<span class="note" style="min-width:3rem">tx</span>
<div class="meter" style="flex:1"><div class="meter-fill" id="meter-tx"></div></div>
<div class="meter" style="width:100%"><div class="meter-fill" id="meter-tx"></div></div>
<span class="note" id="gain-label" style="min-width:3rem; text-align:right">0%</span>
</div>
<div class="row">
<span class="note" style="min-width:3rem">rx</span>
<div class="meter" style="flex:1"><div class="meter-fill" id="meter-rx"></div></div>
<div class="meter" style="width:100%"><div class="meter-fill" id="meter-rx"></div></div>
<span class="note" id="rx-label" style="min-width:3rem; text-align:right"></span>
</div>
</section>
@ -1720,8 +1732,8 @@ logLine('sys', 'chat content lives in encrypted SRTP audio. no IP packets carry
</script>
<footer style="max-width:820px;margin:2.2rem auto 0;font-size:0.65rem;color:#999;line-height:1.7;word-break:break-all;font-family:monospace">
<span style="color:#777">page integrity</span> &nbsp;·&nbsp; built <span class="stamp-date">2026-06-02</span><br>
md5 <span class="stamp-md5">0fb2dca42673efdde9164f5bc24d0200</span><br>
sha256 <span class="stamp-sha">ba3b4ce8b96e2649f76f9b0338bde38ddcdbea148adbdfb0e23094a85999ee2b</span><br>
md5 <span class="stamp-md5">5ae64bcf96a54da7ea55a0df88548920</span><br>
sha256 <span class="stamp-sha">06a3c011ec9670d85c6ab27b8decbfcc4f78e8a9be8186407670fdf4e4cc8dfd</span><br>
<span style="color:#bbb">hashes are of this page with these two fields zeroed — to verify, blank them and re-hash</span><br>
<span style="color:#bbb">one self-contained file — <strong>save a copy</strong> and verify it against these hashes; point it at your own servers with ?signal= and ?turncred=, or <a href="host-your-own.html" style="color:#999">host your own community</a></span>
</footer>