Announcements: stick with the nav, and stop cutting the message

Two faults on a phone, both found on the live site.

The single-line clamp truncated a venue change at 'the Deep Creek
pa...', cutting the only part of the notice that mattered. Collapsed
now clamps to two lines, three under 560px. A SINGLE notice does not
clamp at all - it has no expand affordance, so clamping it loses text
with no way to get it back.

The banner scrolled away while the nav stayed pinned. That was a
deliberate call and it was wrong: a cancellation is worth more
viewport than the nav is. Banner and nav now share one sticky wrapper
so they pin together.

Expanded is exempt via :has() - an open three-notice banner pinned to
a phone viewport is the thing the original call was trying to avoid,
and it is still right about that. Open scrolls, collapsed sticks. The
40vh cap stays as the floor where :has() is unsupported.
This commit is contained in:
claude
2026-09-01 19:26:09 -04:00
parent e02125392a
commit f0acb50190
+17 -7
View File
@@ -271,18 +271,23 @@ footer a.fb{display:inline-flex;align-items:center;gap:8px}
.annc{border-bottom:1px solid;font-family:'Public Sans',system-ui,sans-serif} .annc{border-bottom:1px solid;font-family:'Public Sans',system-ui,sans-serif}
.annc-info{background:#F3EBD8;border-color:#E8DCBB;color:#6B5510} .annc-info{background:#F3EBD8;border-color:#E8DCBB;color:#6B5510}
.annc-urgent{background:#F6E3DA;border-color:#DFB9A4;color:#8A3B1D} .annc-urgent{background:#F6E3DA;border-color:#DFB9A4;color:#8A3B1D}
.anncrow{display:flex;align-items:center;gap:9px;padding:11px 0} .anncrow{display:flex;align-items:flex-start;gap:9px;padding:11px 0}
.topstick{position:sticky;top:0;z-index:60}
.topstick header.nav{position:static}
.topstick:has(.annc[open]){position:static}
.annc summary{cursor:pointer;list-style:none;-webkit-tap-highlight-color:transparent} .annc summary{cursor:pointer;list-style:none;-webkit-tap-highlight-color:transparent}
.annc summary::-webkit-details-marker{display:none} .annc summary::-webkit-details-marker{display:none}
.annc summary:focus-visible{outline:2px solid currentColor;outline-offset:-3px} .annc summary:focus-visible{outline:2px solid currentColor;outline-offset:-3px}
.anncico,.anncchev{flex:none;display:flex;align-items:center} .anncico,.anncchev{flex:none;display:flex;align-items:center;margin-top:1px}
.anncchev{transition:transform .15s ease} .anncchev{transition:transform .15s ease}
.annc[open] .anncchev{transform:rotate(180deg)} .annc[open] .anncchev{transform:rotate(180deg)}
.anncline{flex:1;min-width:0;font-size:14px;line-height:1.35;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .anncline{flex:1;min-width:0;font-size:14px;line-height:1.4;overflow-wrap:anywhere}
.ancctop{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}
@media(max-width:560px){.ancctop{-webkit-line-clamp:3}}
.anncopen{display:none} .anncopen{display:none}
.annc[open] .ancctop{display:none} .annc[open] .ancctop{display:none}
.annc[open] .anncopen{display:block;font-weight:600} .annc[open] .anncopen{display:block;font-weight:600}
.annccount{flex:none;font-size:11px;font-weight:700;padding:1px 7px;border-radius:999px;border:1px solid currentColor} .annccount{flex:none;margin-top:1px;font-size:11px;font-weight:700;padding:1px 7px;border-radius:999px;border:1px solid currentColor}
.annc[open] .annccount{display:none} .annc[open] .annccount{display:none}
.anncbody{max-height:40vh;overflow-y:auto;padding-bottom:12px} .anncbody{max-height:40vh;overflow-y:auto;padding-bottom:12px}
.anncitem{padding:10px 0 0;font-size:14px;line-height:1.5;overflow-wrap:anywhere} .anncitem{padding:10px 0 0;font-size:14px;line-height:1.5;overflow-wrap:anywhere}
@@ -324,7 +329,12 @@ def announcement_bar():
must never take down the public homepage, so any error here renders an must never take down the public homepage, so any error here renders an
empty string and logs. empty string and logs.
Collapsed shows the top-ranked notice on one clamped line plus a count. Collapsed clamps to two lines, three on a phone, because one line cut the
actual location out of a venue change - the only part of the notice that
mattered. A single notice does not clamp at all: it has no expand
affordance, so clamping it would lose text with no way to recover it.
Collapsed shows the top-ranked notice plus a count.
Expanded lists all of them. Native <details>, so there is no JavaScript Expanded lists all of them. Native <details>, so there is no JavaScript
and nothing to load - which matters on a read-only rootfs with no build and nothing to load - which matters on a read-only rootfs with no build
step. The single-notice case, which is nearly always the case, renders step. The single-notice case, which is nearly always the case, renders
@@ -386,7 +396,7 @@ def page(title, body, active=""):
<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@500;600;700;800;900&family=Public+Sans:wght@400;600;700&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Archivo:wght@500;600;700;800;900&family=Public+Sans:wght@400;600;700&display=swap" rel="stylesheet">
<style>{CSS}</style> <style>{CSS}</style>
</head><body style="display:flex;flex-direction:column;min-height:100vh"> </head><body style="display:flex;flex-direction:column;min-height:100vh">
{announcement_bar()} <div class="topstick">{announcement_bar()}
<header class="nav"><div class="wrap navrow"> <header class="nav"><div class="wrap navrow">
<a class="brand" href="/"><img src="/static/img/patch-73.png" alt="Pack and Troop 73 patch"><span><span class="b1">PACK &amp; TROOP 73</span><span class="b2">Zieglerville, PA · Cradle of Liberty Council</span></span></a> <a class="brand" href="/"><img src="/static/img/patch-73.png" alt="Pack and Troop 73 patch"><span><span class="b1">PACK &amp; TROOP 73</span><span class="b2">Zieglerville, PA · Cradle of Liberty Council</span></span></a>
<nav class="links"> <nav class="links">
@@ -395,7 +405,7 @@ def page(title, body, active=""):
<a href="/troop"{on('troop')}>The Troop</a> <a href="/troop"{on('troop')}>The Troop</a>
<a href="/calendar"{on('cal')}>Calendar</a> <a href="/calendar"{on('cal')}>Calendar</a>
<a class="joinbtn" href="/join">Join us</a> <a class="joinbtn" href="/join">Join us</a>
</nav></div></header> </nav></div></header></div>
{body} {body}
<footer><div class="wrap footgrid"> <footer><div class="wrap footgrid">
<div style="max-width:340px"><div style="display:flex;align-items:center;gap:10px;margin-bottom:12px"><img src="/static/img/patch-73.png" alt="" style="width:40px;height:40px;border-radius:50%;object-fit:cover"><span class="arch" style="font-weight:800;letter-spacing:.06em;color:#fff">PACK &amp; TROOP 73</span></div> <div style="max-width:340px"><div style="display:flex;align-items:center;gap:10px;margin-bottom:12px"><img src="/static/img/patch-73.png" alt="" style="width:40px;height:40px;border-radius:50%;object-fit:cover"><span class="arch" style="font-weight:800;letter-spacing:.06em;color:#fff">PACK &amp; TROOP 73</span></div>