site: fix mobile overflow at the cause, and give the header a hamburger

Joe opened the page on a phone and found what I could not: the install
commands pushed the layout sideways, and the header did the same.

ROOT CAUSE, and it was one thing behind both: grid and flex children
default to min-width:auto, so a box holding a long unbreakable string —
a curl command, a terminal block — refuses to shrink below that string
and pushes the whole PAGE sideways instead of scrolling inside itself.
`overflow-x: auto` on the inner element does nothing while its parent
will not shrink. min-width:0 on the children of every grid is the fix,
and it is why the page was fine at 1080px and broken at 390.

The copy blocks also had the button inside the scrolling region, so on a
narrow screen the one control anybody actually uses scrolled out of
reach. The command now scrolls in its own box, the button sits outside
it, and below 720px the command wraps instead of scrolling — the whole
thing visible at once, break-all because a URL has no useful break
points.

HEADER: hiding the nav links on small screens was never a fix, because
the theme switch and the call to action still competed for a 360px bar.
Below 760px the bar now holds the mark and one button, and everything
else moves into a panel: aria-expanded on the control, Escape closes it,
following a link closes it — a panel left open over the thing you just
asked to see is its own bug — and a resize past the breakpoint closes it
so rotating to landscape cannot strand a phone panel over a desktop
layout.

One regression I introduced and caught before it shipped: I had written
`#menu { display: contents }` to make the panel transparent on desktop.
An ID beats a class, so that quietly overrode nav.links's own flex
layout and margin-left:auto and unstuck the desktop navigation from the
right-hand side. The panel styles now live inside the breakpoint and
nowhere else.

I still cannot see this page — the browser here renders with CSS
disabled — so this was reasoned from the cause Joe's report pointed at
rather than from looking. Another pair of eyes on a phone would be worth
having.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hound 2026-08-21 09:35:29 -05:00
parent fe49518383
commit ac28efffb0

View file

@ -92,6 +92,13 @@ body {
}
.wrap { max-width: 1080px; margin: 0 auto; padding: 0 24px; }
/* Grid and flex children default to min-width:auto, so anything holding
a long unbreakable string — a terminal block, a curl command — refuses
to shrink below that string and pushes the whole PAGE sideways instead
of scrolling inside its own box. This is the single most common cause
of a layout that is fine on a desktop and broken on a phone. */
.hero > *, .grid2 > *, .grid3 > *, .tiers > *, .install > *, .stats > * { min-width: 0; }
.mono { font-family: "JetBrains Mono", ui-monospace, monospace; }
a { color: var(--brand); text-decoration: none; }
@ -126,7 +133,46 @@ header {
nav.links { margin-left: auto; display: flex; gap: 22px; align-items: center; }
nav.links a { color: var(--dim); font-size: 14.5px; font-weight: 500; }
nav.links a:hover { color: var(--fg); text-decoration: none; }
@media (max-width: 720px) { nav.links a.hide-sm { display: none; } }
/* Hamburger. Hiding links on a phone was not enough — the theme switch
and the call to action still competed for a 360px bar and pushed it
sideways. Below the breakpoint the bar holds the mark and one button,
and everything else moves into a panel. */
.menu-btn {
display: none; appearance: none; border: 1px solid var(--line-hi);
background: var(--raised); color: var(--fg); cursor: pointer;
border-radius: 9px; padding: 9px; line-height: 0; margin-left: auto;
}
.menu-btn svg { width: 20px; height: 20px; }
.menu-btn .close { display: none; }
.menu-btn[aria-expanded="true"] .open { display: none; }
.menu-btn[aria-expanded="true"] .close { display: block; }
/* No display:contents here. An ID beats a class, so it would override
nav.links's own flex layout and margin-left:auto and quietly unstick
the desktop navigation from the right-hand side. The panel styles
belong inside the breakpoint and nowhere else. */
@media (max-width: 760px) {
.menu-btn { display: inline-flex; }
#menu {
display: none;
position: absolute; left: 0; right: 0; top: 100%;
background: var(--bg); border-bottom: 1px solid var(--line);
padding: 8px 24px 20px;
flex-direction: column; align-items: stretch; gap: 4px;
box-shadow: var(--shadow);
}
#menu.open { display: flex; }
#menu a:not(.btn) {
padding: 13px 4px; border-bottom: 1px solid var(--line);
font-size: 16px; color: var(--fg);
}
#menu .theme { align-self: flex-start; margin: 14px 0 4px; }
#menu .btn { justify-content: center; padding: 13px 17px; }
header { position: sticky; }
.bar { position: relative; }
}
/* theme switch */
.theme {
@ -166,7 +212,7 @@ nav.links a:hover { color: var(--fg); text-decoration: none; }
/* terminal */
.term {
background: var(--term-bg); border: 1px solid var(--line); border-radius: 13px;
box-shadow: var(--shadow); overflow: hidden;
box-shadow: var(--shadow); overflow: hidden; min-width: 0; max-width: 100%;
}
.term-bar {
display: flex; align-items: center; gap: 9px; padding: 10px 14px;
@ -175,7 +221,7 @@ nav.links a:hover { color: var(--fg); text-decoration: none; }
}
.term-bar i { width: 9px; height: 9px; border-radius: 50%; background: #32405A; display: inline-block; }
.term pre {
margin: 0; padding: 16px 18px 20px; overflow-x: auto;
margin: 0; padding: 16px 18px 20px; overflow-x: auto; max-width: 100%;
font: 12.5px/1.75 "JetBrains Mono", ui-monospace, monospace;
color: var(--term-fg);
}
@ -247,17 +293,35 @@ code, .inline {
.copy {
display: flex; align-items: center; gap: 12px;
background: var(--code-bg); border: 1px solid var(--line);
border-radius: 10px; padding: 13px 15px; overflow-x: auto;
border-radius: 10px; padding: 13px 15px;
min-width: 0;
}
/* Only the command scrolls. The button sits outside that box so it can
never be scrolled out of reach — which is what happens when the whole
row is the scroll container. */
.copy .cmd { overflow-x: auto; min-width: 0; flex: 1 1 auto; }
.copy code {
background: none; border: 0; padding: 0; font-size: 13px;
white-space: nowrap; display: block;
}
.copy code { background: none; border: 0; padding: 0; white-space: nowrap; font-size: 13px; }
.copy button {
margin-left: auto; appearance: none; border: 1px solid var(--line-hi);
appearance: none; border: 1px solid var(--line-hi);
background: var(--raised); color: var(--dim); cursor: pointer;
font: 500 12px/1 "IBM Plex Sans", system-ui, sans-serif;
padding: 6px 10px; border-radius: 6px; flex: 0 0 auto;
padding: 7px 11px; border-radius: 6px; flex: 0 0 auto;
}
.copy button:hover { color: var(--fg); }
/* On a phone, wrapping beats sideways scrolling: the whole command is
visible at once, and the Copy button is the thing they will use
anyway. break-all because a URL has no useful break points. */
@media (max-width: 720px) {
.copy { align-items: flex-start; flex-direction: column; gap: 10px; }
.copy .cmd { overflow-x: visible; width: 100%; }
.copy code { white-space: pre-wrap; word-break: break-all; line-height: 1.7; }
.copy button { align-self: flex-end; }
}
/* ── footer ───────────────────────────────────────────────────────── */
footer { border-top: 1px solid var(--line); padding: 40px 0 56px; color: var(--faint); font-size: 13.5px; }
.foot { display: flex; gap: 28px; flex-wrap: wrap; align-items: center; }
@ -274,9 +338,13 @@ footer { border-top: 1px solid var(--line); padding: 40px 0 56px; color: var(--f
<svg viewBox="0 0 28 28" aria-hidden="true"><rect width="28" height="28" rx="6.3" fill="var(--brand)"/><g transform="translate(3.2,3.2) scale(0.771)" fill="var(--on-brand)" fill-rule="nonzero"><path d="M3.80069371,23.1130888 C4.43848107,23.5650959 5.14832497,23.919844 5.9089202,24.1573863 L4.47060635,26.3139954 C4.11309659,26.8500464 3.3887224,26.9947828 2.85267132,26.637273 C2.35490959,26.3052997 2.19455701,25.6569993 2.46043143,25.1368862 L2.52939365,25.019338 L3.80069371,23.1130888 Z M14.5833333,1.16666667 C16.7811895,1.16666667 18.6893658,2.52489596 19.4646473,4.47968116 L19.5335,4.66666667 L24.3833333,4.66666667 C25.0448446,4.66666667 25.5894608,5.16717524 25.6591362,5.81016498 L25.6666667,5.94999885 L25.6666667,11.375 C25.6666667,14.0328704 23.5754085,16.2023012 20.9485691,16.3276156 L20.7083333,16.3333333 L18.7961667,16.3321667 L18.8104203,16.3635263 C19.2754933,17.3735749 19.6443042,18.3167095 19.9164818,19.1943797 L20.0445161,19.627766 C20.7657518,22.2003082 19.7286621,25.1941618 17.5638169,26.637392 C17.0277001,26.9948032 16.3033525,26.8499337 15.9459413,26.3138169 C15.5885301,25.7777001 15.7333996,25.0533525 16.2695164,24.6959413 C17.5764793,23.8246327 18.2515149,21.8759509 17.7978097,20.2576506 C17.4455369,19.0011449 16.8372737,17.5384042 15.9713012,15.8761384 C15.8759396,15.6930882 15.8261459,15.4897339 15.8261459,15.2833333 C15.8261459,14.6231337 16.3245332,14.0799436 16.9690039,14.0080605 L17.1092123,14 L20.7083333,14 C22.0976747,14 23.2349191,12.9206448 23.3272774,11.5547236 L23.3333333,11.375 L23.3333333,6.99883333 L17.6136472,7.00006824 L17.4704091,5.99857195 C17.2758266,4.63808519 16.1483073,3.59829995 14.780321,3.50658494 L14.5833333,3.5 L12.7831667,3.5 L12.5783017,3.50389564 C8.27042644,3.63569563 4.8164366,7.09906173 4.67140846,11.3859455 L4.66666667,11.6666667 L4.66631609,16.8880679 L4.67097109,17.092305 C4.76225687,18.9495018 6.29888585,20.4166667 8.16666667,20.4166667 C10.0996633,20.4166667 11.6666667,18.8496633 11.6666667,16.9166667 C11.6666667,16.1268183 11.523797,15.416107 11.2062777,14.4675176 L10.7570788,13.2056109 C10.1975498,11.6462738 9.90930052,10.544355 9.77521466,9.11410583 C9.71507223,8.47258663 10.1863712,7.90377749 10.8278904,7.84363507 C11.4694096,7.78349264 12.0382188,8.25479164 12.0983612,8.89631084 C12.1996371,9.97658728 12.4067419,10.8376191 12.8110905,12.0132787 L13.3678001,13.5759215 L13.4189446,13.7268763 C13.8098537,14.8947176 14,15.8406089 14,16.9166667 C14,20.1383277 11.3883277,22.75 8.16666667,22.75 C5.13975753,22.75 2.63542176,20.439154 2.35770657,17.4371488 L2.3393951,17.1781792 L2.33333333,16.9166667 L2.33333333,11.6666667 C2.33333333,6.09263102 6.68344803,1.51408374 12.2162292,1.1851268 L12.4308333,1.17483333 L12.4315796,1.16666667 L14.5833333,1.16666667 Z M16.1504743,6.81070338 L16.4543586,8.53411695 C16.5662457,9.1686603 16.1425491,9.77376175 15.5080058,9.88564887 C14.8734624,9.99753598 14.268361,9.57383938 14.1564739,8.93929603 L13.8525895,7.21588246 C13.7407024,6.58133911 14.164399,5.97623765 14.7989424,5.86435054 C15.4334857,5.75246343 16.0385872,6.17616002 16.1504743,6.81070338 Z"></path></g></svg>
<b>Hound</b>
</a>
<nav class="links">
<a href="#what" class="hide-sm">What it catches</a>
<a href="#agents" class="hide-sm">For agents</a>
<button class="menu-btn" id="menu-btn" aria-expanded="false" aria-controls="menu" aria-label="Menu">
<svg class="open" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M3 6h18M3 12h18M3 18h18"/></svg>
<svg class="close" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
<nav class="links" id="menu">
<a href="#what">What it catches</a>
<a href="#agents">For agents</a>
<a href="#pricing">Pricing</a>
<div class="theme" role="group" aria-label="Colour theme">
<button data-set="light" aria-pressed="false" title="Light">
@ -513,14 +581,14 @@ footer { border-top: 1px solid var(--line); padding: 40px 0 56px; color: var(--f
<div>
<p style="color:var(--dim); font-size:14px; margin-bottom:10px;"><strong style="color:var(--fg)">Debian, Ubuntu, Mint</strong></p>
<div class="copy">
<code id="c1">curl -fsSL https://dl.houndav.com/deb/hound_latest_amd64.deb -o hound.deb &amp;&amp; sudo apt install ./hound.deb</code>
<div class="cmd"><code id="c1">curl -fsSL https://dl.houndav.com/deb/hound_latest_amd64.deb -o hound.deb &amp;&amp; sudo apt install ./hound.deb</code></div>
<button data-copy="c1">Copy</button>
</div>
</div>
<div>
<p style="color:var(--dim); font-size:14px; margin-bottom:10px;"><strong style="color:var(--fg)">Try it without installing</strong></p>
<div class="copy">
<code id="c2">curl -fsSL https://dl.houndav.com/appimage/Hound-latest-x86_64.AppImage -o hound &amp;&amp; chmod +x hound &amp;&amp; ./hound status</code>
<div class="cmd"><code id="c2">curl -fsSL https://dl.houndav.com/appimage/Hound-latest-x86_64.AppImage -o hound &amp;&amp; chmod +x hound &amp;&amp; ./hound status</code></div>
<button data-copy="c2">Copy</button>
</div>
</div>
@ -587,6 +655,32 @@ footer { border-top: 1px solid var(--line); padding: 40px 0 56px; color: var(--f
});
});
// Hamburger
var menuBtn = document.getElementById('menu-btn');
var menu = document.getElementById('menu');
function setMenu(open) {
menu.classList.toggle('open', open);
menuBtn.setAttribute('aria-expanded', String(open));
}
if (menuBtn && menu) {
menuBtn.addEventListener('click', function () {
setMenu(menuBtn.getAttribute('aria-expanded') !== 'true');
});
// Any navigation closes it, or the panel stays over the thing you
// just asked to see.
menu.addEventListener('click', function (e) {
if (e.target.closest('a')) setMenu(false);
});
document.addEventListener('keydown', function (e) {
if (e.key === 'Escape') setMenu(false);
});
// Rotating to landscape must not leave a phone panel stranded over a
// desktop layout.
window.addEventListener('resize', function () {
if (window.innerWidth > 760) setMenu(false);
});
}
document.querySelectorAll('[data-copy]').forEach(function (btn) {
btn.addEventListener('click', function () {
var el = document.getElementById(btn.dataset.copy);